mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-06-20 18:00:52 +00:00
refactor: 输出格式重构,去掉所有插件的多线程,因为多线程会导致结果不准确,加入进度条
This commit is contained in:
parent
277ea5d332
commit
ceede3cd68
@ -1,5 +1,10 @@
|
|||||||
package Common
|
package Common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/schollz/progressbar/v3"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
var version = "2.0.0"
|
var version = "2.0.0"
|
||||||
var Userdict = map[string][]string{
|
var Userdict = map[string][]string{
|
||||||
"ftp": {"ftp", "admin", "www", "web", "root", "db", "wwwroot", "data"},
|
"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 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 Outputfile = "result.txt"
|
||||||
var IsSave = true
|
|
||||||
|
// 添加一个全局的进度条变量
|
||||||
|
var ProgressBar *progressbar.ProgressBar
|
||||||
|
|
||||||
|
// 添加一个全局互斥锁来控制输出
|
||||||
|
var OutputMutex sync.Mutex
|
||||||
|
|
||||||
type PocInfo struct {
|
type PocInfo struct {
|
||||||
Target string
|
Target string
|
||||||
|
@ -113,7 +113,6 @@ func Flag(Info *HostInfo) {
|
|||||||
|
|
||||||
// 暴力破解配置
|
// 暴力破解配置
|
||||||
flag.BoolVar(&DisableBrute, "nobr", false, "禁用密码暴力破解")
|
flag.BoolVar(&DisableBrute, "nobr", false, "禁用密码暴力破解")
|
||||||
flag.IntVar(&BruteThreads, "br", 1, "设置密码破解线程数")
|
|
||||||
flag.IntVar(&MaxRetries, "retry", 3, "设置最大重试次数")
|
flag.IntVar(&MaxRetries, "retry", 3, "设置最大重试次数")
|
||||||
|
|
||||||
// 其他配置
|
// 其他配置
|
||||||
@ -128,7 +127,7 @@ func Flag(Info *HostInfo) {
|
|||||||
flag.BoolVar(&Silent, "silent", false, "启用静默扫描模式(减少屏幕输出)")
|
flag.BoolVar(&Silent, "silent", false, "启用静默扫描模式(减少屏幕输出)")
|
||||||
flag.BoolVar(&NoColor, "nocolor", false, "禁用彩色输出显示")
|
flag.BoolVar(&NoColor, "nocolor", false, "禁用彩色输出显示")
|
||||||
flag.BoolVar(&JsonFormat, "json", false, "以JSON格式输出结果")
|
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()
|
flag.Parse()
|
||||||
}
|
}
|
||||||
|
218
Common/Log.go
218
Common/Log.go
@ -18,19 +18,14 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
// 全局变量
|
// 全局变量
|
||||||
status = &ScanStatus{lastSuccess: time.Now(), lastError: time.Now()}
|
status = &ScanStatus{lastSuccess: time.Now(), lastError: time.Now()}
|
||||||
results = make(chan *LogEntry, 1000) // 使用缓冲通道
|
|
||||||
logWG sync.WaitGroup
|
|
||||||
|
|
||||||
// 扫描计数
|
// 扫描计数
|
||||||
Num int64 // 总任务数
|
Num int64 // 总任务数
|
||||||
End int64 // 已完成任务数
|
End int64 // 已完成任务数
|
||||||
)
|
|
||||||
|
|
||||||
// 将 results 改名为 Results 使其可导出
|
// 文件写入器
|
||||||
var (
|
fileWriter *bufferedFileWriter
|
||||||
Results = results // 使 results 可导出
|
|
||||||
LogWG = logWG // 使 logWG 可导出
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ScanStatus 记录扫描状态
|
// ScanStatus 记录扫描状态
|
||||||
@ -66,16 +61,18 @@ var logColors = map[string]color.Attribute{
|
|||||||
LogLevelDebug: color.FgBlue,
|
LogLevelDebug: color.FgBlue,
|
||||||
}
|
}
|
||||||
|
|
||||||
// bufferedFileWriter 文件写入器
|
// JsonOutput JSON输出的结构体
|
||||||
type bufferedFileWriter struct {
|
type JsonOutput struct {
|
||||||
file *os.File
|
Level string `json:"level"`
|
||||||
writer *bufio.Writer
|
Timestamp time.Time `json:"timestamp"`
|
||||||
jsonEnc *json.Encoder
|
Message string `json:"message"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func InitLogger() {
|
||||||
log.SetOutput(io.Discard)
|
log.SetOutput(io.Discard)
|
||||||
go processLogs()
|
if !DisableSave {
|
||||||
|
fileWriter = newBufferedFileWriter()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// formatLogMessage 格式化日志消息
|
// formatLogMessage 格式化日志消息
|
||||||
@ -85,124 +82,108 @@ func formatLogMessage(entry *LogEntry) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func printLog(entry *LogEntry) {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OutputMutex.Lock()
|
||||||
|
defer OutputMutex.Unlock()
|
||||||
|
|
||||||
logMsg := formatLogMessage(entry)
|
logMsg := formatLogMessage(entry)
|
||||||
if NoColor {
|
// 只在输出到终端时处理进度条
|
||||||
fmt.Println(logMsg)
|
if !NoColor {
|
||||||
return
|
// 清除当前行
|
||||||
}
|
fmt.Print("\033[2K\r")
|
||||||
|
if colorAttr, ok := logColors[entry.Level]; ok {
|
||||||
if colorAttr, ok := logColors[entry.Level]; ok {
|
color.New(colorAttr).Println(logMsg)
|
||||||
color.New(colorAttr).Println(logMsg)
|
} else {
|
||||||
|
fmt.Println(logMsg)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Println(logMsg)
|
fmt.Println(logMsg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 同样修改 LogError 和 LogInfo
|
|
||||||
func LogError(errMsg string) {
|
func LogError(errMsg string) {
|
||||||
// 获取调用者信息
|
|
||||||
_, file, line, ok := runtime.Caller(1)
|
_, file, line, ok := runtime.Caller(1)
|
||||||
if !ok {
|
if !ok {
|
||||||
file = "unknown"
|
file = "unknown"
|
||||||
line = 0
|
line = 0
|
||||||
}
|
}
|
||||||
// 只获取文件名
|
|
||||||
file = filepath.Base(file)
|
file = filepath.Base(file)
|
||||||
|
|
||||||
// 格式化错误消息
|
|
||||||
errorMsg := fmt.Sprintf("%s:%d - %s", file, line, errMsg)
|
errorMsg := fmt.Sprintf("%s:%d - %s", file, line, errMsg)
|
||||||
|
|
||||||
select {
|
if ProgressBar != nil {
|
||||||
case Results <- &LogEntry{
|
ProgressBar.Clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
entry := &LogEntry{
|
||||||
Level: LogLevelError,
|
Level: LogLevelError,
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Content: errorMsg,
|
Content: errorMsg,
|
||||||
}:
|
}
|
||||||
logWG.Add(1)
|
|
||||||
default:
|
printLog(entry)
|
||||||
printLog(&LogEntry{
|
if fileWriter != nil {
|
||||||
Level: LogLevelError,
|
fileWriter.write(entry)
|
||||||
Time: time.Now(),
|
}
|
||||||
Content: errorMsg,
|
|
||||||
})
|
if ProgressBar != nil {
|
||||||
|
ProgressBar.RenderBlank()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func LogInfo(msg string) {
|
func LogInfo(msg string) {
|
||||||
select {
|
if ProgressBar != nil {
|
||||||
case Results <- &LogEntry{
|
ProgressBar.Clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
entry := &LogEntry{
|
||||||
Level: LogLevelInfo,
|
Level: LogLevelInfo,
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Content: msg,
|
Content: msg,
|
||||||
}:
|
}
|
||||||
logWG.Add(1)
|
|
||||||
default:
|
printLog(entry)
|
||||||
printLog(&LogEntry{
|
if fileWriter != nil {
|
||||||
Level: LogLevelInfo,
|
fileWriter.write(entry)
|
||||||
Time: time.Now(),
|
}
|
||||||
Content: msg,
|
|
||||||
})
|
if ProgressBar != nil {
|
||||||
|
ProgressBar.RenderBlank()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LogSuccess 记录成功信息
|
|
||||||
func LogSuccess(result string) {
|
func LogSuccess(result string) {
|
||||||
// 添加通道关闭检查
|
if ProgressBar != nil {
|
||||||
select {
|
ProgressBar.Clear()
|
||||||
case Results <- &LogEntry{
|
}
|
||||||
|
|
||||||
|
entry := &LogEntry{
|
||||||
Level: LogLevelSuccess,
|
Level: LogLevelSuccess,
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Content: result,
|
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输出的结构体
|
printLog(entry)
|
||||||
type JsonOutput struct {
|
if fileWriter != nil {
|
||||||
Level string `json:"level"`
|
fileWriter.write(entry)
|
||||||
Timestamp time.Time `json:"timestamp"`
|
}
|
||||||
Message string `json:"message"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// processLogs 处理日志信息
|
status.mu.Lock()
|
||||||
func processLogs() {
|
status.lastSuccess = time.Now()
|
||||||
writer := newBufferedFileWriter()
|
status.mu.Unlock()
|
||||||
defer writer.close()
|
|
||||||
|
|
||||||
for entry := range results {
|
if ProgressBar != nil {
|
||||||
if !Silent {
|
ProgressBar.RenderBlank()
|
||||||
printLog(entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
if writer != nil {
|
|
||||||
writer.write(entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
logWG.Done()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newBufferedFileWriter() *bufferedFileWriter {
|
func newBufferedFileWriter() *bufferedFileWriter {
|
||||||
if DisableSave {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
file, err := os.OpenFile(Outputfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
|
file, err := os.OpenFile(Outputfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("[ERROR] 打开输出文件失败 %s: %v\n", Outputfile, err)
|
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) {
|
func (w *bufferedFileWriter) write(entry *LogEntry) {
|
||||||
if w == nil {
|
if w == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
w.mu.Lock()
|
||||||
|
defer w.mu.Unlock()
|
||||||
|
|
||||||
|
var err error
|
||||||
if JsonFormat {
|
if JsonFormat {
|
||||||
output := JsonOutput{
|
output := JsonOutput{
|
||||||
Level: entry.Level,
|
Level: entry.Level,
|
||||||
Timestamp: entry.Time,
|
Timestamp: entry.Time,
|
||||||
Message: entry.Content,
|
Message: entry.Content,
|
||||||
}
|
}
|
||||||
if err := w.jsonEnc.Encode(output); err != nil {
|
err = w.jsonEnc.Encode(output)
|
||||||
fmt.Printf("[ERROR] JSON编码失败: %v\n", err)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
logMsg := formatLogMessage(entry) + "\n"
|
logMsg := formatLogMessage(entry) + "\n"
|
||||||
if _, err := w.writer.WriteString(logMsg); err != nil {
|
_, err = w.writer.WriteString(logMsg)
|
||||||
fmt.Printf("[ERROR] 写入文件失败: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
func (w *bufferedFileWriter) close() {
|
||||||
@ -248,6 +268,12 @@ func (w *bufferedFileWriter) close() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CloseLogger() {
|
||||||
|
if fileWriter != nil {
|
||||||
|
fileWriter.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CheckErrs 检查是否为需要重试的错误
|
// CheckErrs 检查是否为需要重试的错误
|
||||||
func CheckErrs(err error) error {
|
func CheckErrs(err error) error {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -223,10 +223,10 @@ func ParseInput(Info *HostInfo) error {
|
|||||||
LogInfo(fmt.Sprintf("暴力破解线程数: %d", BruteThreads))
|
LogInfo(fmt.Sprintf("暴力破解线程数: %d", BruteThreads))
|
||||||
}
|
}
|
||||||
|
|
||||||
if DisableSave {
|
//if DisableSave {
|
||||||
IsSave = false
|
// IsSave = false
|
||||||
LogInfo("已启用临时保存模式")
|
// LogInfo("已启用临时保存模式")
|
||||||
}
|
//}
|
||||||
|
|
||||||
// 处理端口配置
|
// 处理端口配置
|
||||||
if Ports == MainPorts {
|
if Ports == MainPorts {
|
||||||
|
@ -21,7 +21,7 @@ var pluginGroups = map[string][]string{
|
|||||||
"web", "fcgi", // web类
|
"web", "fcgi", // web类
|
||||||
"mysql", "mssql", "redis", "mongodb", "postgres", // 数据库类
|
"mysql", "mssql", "redis", "mongodb", "postgres", // 数据库类
|
||||||
"oracle", "memcached", "elasticsearch", "rabbitmq", "kafka", "activemq", "cassandra", "neo4j", // 数据库类
|
"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", // 漏洞类
|
"ms17010", "smbghost", "smb2", // 漏洞类
|
||||||
"findnet", // 其他
|
"findnet", // 其他
|
||||||
},
|
},
|
||||||
@ -36,7 +36,7 @@ var pluginGroups = map[string][]string{
|
|||||||
"web", "fcgi",
|
"web", "fcgi",
|
||||||
},
|
},
|
||||||
ModeService: {
|
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: {
|
ModeVul: {
|
||||||
"ms17010", "smbghost", "smb2",
|
"ms17010", "smbghost", "smb2",
|
||||||
|
12
Core/ICMP.go
12
Core/ICMP.go
@ -57,7 +57,7 @@ func handleAliveHosts(chanHosts chan string, hostslist []string, isPing bool) {
|
|||||||
if isPing {
|
if isPing {
|
||||||
protocol = "PING"
|
protocol = "PING"
|
||||||
}
|
}
|
||||||
fmt.Printf("[+] 目标 %-15s 存活 (%s)\n", ip, protocol)
|
fmt.Printf("目标 %-15s 存活 (%s)\n", ip, protocol)
|
||||||
}
|
}
|
||||||
|
|
||||||
AliveHosts = append(AliveHosts, ip)
|
AliveHosts = append(AliveHosts, ip)
|
||||||
@ -76,7 +76,7 @@ func probeWithICMP(hostslist []string, chanHosts chan string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Common.LogError(fmt.Sprintf("ICMP监听失败: %v", err))
|
Common.LogError(fmt.Sprintf("ICMP监听失败: %v", err))
|
||||||
fmt.Println("[-] 正在尝试无监听ICMP探测...")
|
fmt.Println("正在尝试无监听ICMP探测...")
|
||||||
|
|
||||||
// 尝试无监听ICMP探测
|
// 尝试无监听ICMP探测
|
||||||
conn2, err := net.DialTimeout("ip4:icmp", "127.0.0.1", 3*time.Second)
|
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))
|
Common.LogError(fmt.Sprintf("ICMP连接失败: %v", err))
|
||||||
fmt.Println("[-] 当前用户权限不足,无法发送ICMP包")
|
fmt.Println("当前用户权限不足,无法发送ICMP包")
|
||||||
fmt.Println("[*] 切换为PING方式探测...")
|
fmt.Println("切换为PING方式探测...")
|
||||||
|
|
||||||
// 降级使用ping探测
|
// 降级使用ping探测
|
||||||
RunPing(hostslist, chanHosts)
|
RunPing(hostslist, chanHosts)
|
||||||
@ -100,7 +100,7 @@ func printAliveStats(hostslist []string) {
|
|||||||
if len(hostslist) > 1000 {
|
if len(hostslist) > 1000 {
|
||||||
arrTop, arrLen := ArrayCountValueTop(AliveHosts, Common.LiveTop, true)
|
arrTop, arrLen := ArrayCountValueTop(AliveHosts, Common.LiveTop, true)
|
||||||
for i := 0; i < len(arrTop); i++ {
|
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)
|
Common.LogSuccess(output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -109,7 +109,7 @@ func printAliveStats(hostslist []string) {
|
|||||||
if len(hostslist) > 256 {
|
if len(hostslist) > 256 {
|
||||||
arrTop, arrLen := ArrayCountValueTop(AliveHosts, Common.LiveTop, false)
|
arrTop, arrLen := ArrayCountValueTop(AliveHosts, Common.LiveTop, false)
|
||||||
for i := 0; i < len(arrTop); i++ {
|
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)
|
Common.LogSuccess(output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ func init() {
|
|||||||
|
|
||||||
Common.RegisterPlugin("activemq", Common.ScanPlugin{
|
Common.RegisterPlugin("activemq", Common.ScanPlugin{
|
||||||
Name: "ActiveMQ",
|
Name: "ActiveMQ",
|
||||||
Ports: []int{61616, 61613},
|
Ports: []int{61613},
|
||||||
ScanFunc: Plugins.ActiveMQScan,
|
ScanFunc: Plugins.ActiveMQScan,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -115,12 +115,6 @@ func init() {
|
|||||||
ScanFunc: Plugins.SNMPScan,
|
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{
|
Common.RegisterPlugin("modbus", Common.ScanPlugin{
|
||||||
Name: "Modbus",
|
Name: "Modbus",
|
||||||
Ports: []int{502, 5020}, // Modbus 默认端口
|
Ports: []int{502, 5020}, // Modbus 默认端口
|
||||||
|
108
Core/Scanner.go
108
Core/Scanner.go
@ -2,12 +2,15 @@ package Core
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/schollz/progressbar/v3"
|
||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
"github.com/shadow1ng/fscan/WebScan/lib"
|
"github.com/shadow1ng/fscan/WebScan/lib"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Scan 执行扫描主流程
|
// Scan 执行扫描主流程
|
||||||
@ -108,13 +111,68 @@ func executeScans(targets []Common.HostInfo, ch *chan struct{}, wg *sync.WaitGro
|
|||||||
|
|
||||||
if plugins := Common.GetPluginsForMode(mode); plugins != nil {
|
if plugins := Common.GetPluginsForMode(mode); plugins != nil {
|
||||||
pluginsToRun = plugins
|
pluginsToRun = plugins
|
||||||
Common.LogInfo(fmt.Sprintf("加载插件组: %s", mode))
|
|
||||||
} else {
|
} else {
|
||||||
pluginsToRun = []string{mode}
|
pluginsToRun = []string{mode}
|
||||||
isSinglePlugin = true
|
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 {
|
for _, target := range targets {
|
||||||
targetPort, _ := strconv.Atoi(target.Ports)
|
targetPort, _ := strconv.Atoi(target.Ports)
|
||||||
|
|
||||||
@ -127,66 +185,82 @@ func executeScans(targets []Common.HostInfo, ch *chan struct{}, wg *sync.WaitGro
|
|||||||
|
|
||||||
if Common.LocalScan {
|
if Common.LocalScan {
|
||||||
if len(plugin.Ports) == 0 {
|
if len(plugin.Ports) == 0 {
|
||||||
|
loadedPlugins = append(loadedPlugins, pluginName)
|
||||||
AddScan(pluginName, target, ch, wg)
|
AddScan(pluginName, target, ch, wg)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if isSinglePlugin {
|
if isSinglePlugin {
|
||||||
|
loadedPlugins = append(loadedPlugins, pluginName)
|
||||||
AddScan(pluginName, target, ch, wg)
|
AddScan(pluginName, target, ch, wg)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(plugin.Ports) > 0 {
|
if len(plugin.Ports) > 0 {
|
||||||
if plugin.HasPort(targetPort) {
|
if plugin.HasPort(targetPort) {
|
||||||
|
loadedPlugins = append(loadedPlugins, pluginName)
|
||||||
AddScan(pluginName, target, ch, wg)
|
AddScan(pluginName, target, ch, wg)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
loadedPlugins = append(loadedPlugins, pluginName)
|
||||||
AddScan(pluginName, target, ch, wg)
|
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 完成扫描任务
|
// finishScan 完成扫描任务
|
||||||
func finishScan(wg *sync.WaitGroup) {
|
func finishScan(wg *sync.WaitGroup) {
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
// 先发送最后的成功消息
|
// 确保进度条完成
|
||||||
|
Common.ProgressBar.Finish()
|
||||||
|
fmt.Println() // 添加一个换行
|
||||||
Common.LogSuccess(fmt.Sprintf("扫描已完成: %v/%v", Common.End, Common.Num))
|
Common.LogSuccess(fmt.Sprintf("扫描已完成: %v/%v", Common.End, Common.Num))
|
||||||
// 等待日志处理完成后再关闭通道
|
|
||||||
Common.LogWG.Wait()
|
|
||||||
close(Common.Results)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mutex用于保护共享资源的并发访问
|
// Mutex用于保护共享资源的并发访问
|
||||||
var Mutex = &sync.Mutex{}
|
var Mutex = &sync.Mutex{}
|
||||||
|
|
||||||
// AddScan 添加扫描任务到并发队列
|
// AddScan 也需要修改
|
||||||
func AddScan(plugin string, info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
func AddScan(plugin string, info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||||
// 获取信号量,控制并发数
|
|
||||||
*ch <- struct{}{}
|
*ch <- struct{}{}
|
||||||
// 添加等待组计数
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
|
|
||||||
// 启动goroutine执行扫描任务
|
|
||||||
go func() {
|
go func() {
|
||||||
defer func() {
|
defer func() {
|
||||||
wg.Done() // 完成任务后减少等待组计数
|
wg.Done()
|
||||||
<-*ch // 释放信号量
|
<-*ch
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// 增加总任务数
|
|
||||||
Mutex.Lock()
|
Mutex.Lock()
|
||||||
atomic.AddInt64(&Common.Num, 1)
|
atomic.AddInt64(&Common.Num, 1)
|
||||||
Mutex.Unlock()
|
Mutex.Unlock()
|
||||||
|
|
||||||
// 执行扫描
|
|
||||||
ScanFunc(&plugin, &info)
|
ScanFunc(&plugin, &info)
|
||||||
|
|
||||||
// 增加已完成任务数
|
Common.OutputMutex.Lock()
|
||||||
Mutex.Lock()
|
|
||||||
atomic.AddInt64(&Common.End, 1)
|
atomic.AddInt64(&Common.End, 1)
|
||||||
Mutex.Unlock()
|
if Common.ProgressBar != nil {
|
||||||
|
// 清除当前行
|
||||||
|
fmt.Print("\033[2K\r")
|
||||||
|
Common.ProgressBar.Add(1)
|
||||||
|
}
|
||||||
|
Common.OutputMutex.Unlock()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ func MyPluginScan(info *Common.HostInfo) error {
|
|||||||
|
|
||||||
// 3. 处理结果
|
// 3. 处理结果
|
||||||
if result.Vulnerable {
|
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
|
return nil
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -16,7 +15,6 @@ func ActiveMQScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
maxRetries := Common.MaxRetries
|
maxRetries := Common.MaxRetries
|
||||||
threads := Common.BruteThreads
|
|
||||||
|
|
||||||
// 首先测试默认账户
|
// 首先测试默认账户
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
@ -35,103 +33,60 @@ func ActiveMQScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建任务通道
|
starttime := time.Now().Unix()
|
||||||
taskChan := make(chan struct {
|
|
||||||
user string
|
|
||||||
pass string
|
|
||||||
}, len(Common.Userdict["activemq"])*len(Common.Passwords))
|
|
||||||
|
|
||||||
resultChan := make(chan error, threads)
|
// 遍历所有用户名密码组合
|
||||||
|
|
||||||
// 生成所有用户名密码组合任务
|
|
||||||
for _, user := range Common.Userdict["activemq"] {
|
for _, user := range Common.Userdict["activemq"] {
|
||||||
for _, pass := range Common.Passwords {
|
for _, pass := range Common.Passwords {
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
pass = strings.Replace(pass, "{user}", user, -1)
|
||||||
taskChan <- struct {
|
|
||||||
user string
|
|
||||||
pass string
|
|
||||||
}{user, pass}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(taskChan)
|
|
||||||
|
|
||||||
// 启动工作线程
|
// 检查是否超时
|
||||||
var wg sync.WaitGroup
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
for i := 0; i < threads; i++ {
|
return fmt.Errorf("扫描超时")
|
||||||
wg.Add(1)
|
}
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
starttime := time.Now().Unix()
|
|
||||||
|
|
||||||
for task := range taskChan {
|
// 重试循环
|
||||||
// 重试循环
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
// 执行连接测试
|
||||||
// 检查是否超时
|
done := make(chan struct {
|
||||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
success bool
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
err error
|
||||||
return
|
})
|
||||||
}
|
|
||||||
|
|
||||||
// 执行连接测试
|
go func(user, pass string) {
|
||||||
done := make(chan struct {
|
flag, err := ActiveMQConn(info, user, pass)
|
||||||
|
done <- struct {
|
||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
})
|
}{flag, err}
|
||||||
|
}(user, pass)
|
||||||
|
|
||||||
go func(user, pass string) {
|
// 等待结果或超时
|
||||||
flag, err := ActiveMQConn(info, user, pass)
|
var err error
|
||||||
done <- struct {
|
select {
|
||||||
success bool
|
case result := <-done:
|
||||||
err error
|
err = result.err
|
||||||
}{flag, err}
|
if result.success {
|
||||||
}(task.user, task.pass)
|
return nil
|
||||||
|
|
||||||
// 等待结果或超时
|
|
||||||
var err error
|
|
||||||
select {
|
|
||||||
case result := <-done:
|
|
||||||
err = result.err
|
|
||||||
if result.success {
|
|
||||||
resultChan <- nil
|
|
||||||
return
|
|
||||||
}
|
|
||||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
|
||||||
err = fmt.Errorf("连接超时")
|
|
||||||
}
|
}
|
||||||
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
if err != nil {
|
err = fmt.Errorf("连接超时")
|
||||||
errlog := fmt.Sprintf("ActiveMQ服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
|
||||||
Common.LogError(errlog)
|
|
||||||
|
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
|
||||||
if retryCount == maxRetries-1 {
|
|
||||||
resultChan <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
resultChan <- nil
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 等待所有线程完成
|
if err != nil {
|
||||||
go func() {
|
errlog := fmt.Sprintf("ActiveMQ服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
||||||
wg.Wait()
|
info.Host, info.Ports, user, pass, err)
|
||||||
close(resultChan)
|
Common.LogError(errlog)
|
||||||
}()
|
|
||||||
|
|
||||||
// 检查结果
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
for err := range resultChan {
|
if retryCount == maxRetries-1 {
|
||||||
if err != nil {
|
return err
|
||||||
tmperr = err
|
}
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
continue
|
||||||
return err
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -171,7 +126,7 @@ func ActiveMQConn(info *Common.HostInfo, user string, pass string) (bool, error)
|
|||||||
response := string(respBuf[:n])
|
response := string(respBuf[:n])
|
||||||
|
|
||||||
if strings.Contains(response, "CONNECTED") {
|
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)
|
info.Host, info.Ports, user, pass)
|
||||||
Common.LogSuccess(result)
|
Common.LogSuccess(result)
|
||||||
return true, nil
|
return true, nil
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -16,7 +15,6 @@ func CassandraScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
maxRetries := Common.MaxRetries
|
maxRetries := Common.MaxRetries
|
||||||
threads := Common.BruteThreads
|
|
||||||
starttime := time.Now().Unix()
|
starttime := time.Now().Unix()
|
||||||
|
|
||||||
// 首先测试无认证访问
|
// 首先测试无认证访问
|
||||||
@ -34,103 +32,60 @@ func CassandraScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
break
|
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 _, user := range Common.Userdict["cassandra"] {
|
||||||
for _, pass := range Common.Passwords {
|
for _, pass := range Common.Passwords {
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
pass = strings.Replace(pass, "{user}", user, -1)
|
||||||
taskChan <- struct {
|
|
||||||
user string
|
|
||||||
pass string
|
|
||||||
}{user, pass}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(taskChan)
|
|
||||||
|
|
||||||
// 启动工作线程
|
// 检查是否超时
|
||||||
var wg sync.WaitGroup
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
for i := 0; i < threads; i++ {
|
return fmt.Errorf("扫描超时")
|
||||||
wg.Add(1)
|
}
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
for task := range taskChan {
|
|
||||||
// 重试循环
|
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
|
||||||
// 检查是否超时
|
|
||||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 执行连接
|
// 重试循环
|
||||||
done := make(chan struct {
|
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
|
success bool
|
||||||
err error
|
err error
|
||||||
})
|
}{success, err}
|
||||||
|
}(user, pass)
|
||||||
|
|
||||||
go func(user, pass string) {
|
// 等待结果或超时
|
||||||
success, err := CassandraConn(info, user, pass)
|
var err error
|
||||||
done <- struct {
|
select {
|
||||||
success bool
|
case result := <-done:
|
||||||
err error
|
err = result.err
|
||||||
}{success, err}
|
if result.success && err == nil {
|
||||||
}(task.user, task.pass)
|
return nil
|
||||||
|
|
||||||
// 等待结果或超时
|
|
||||||
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("连接超时")
|
|
||||||
}
|
}
|
||||||
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
// 处理错误情况
|
err = fmt.Errorf("连接超时")
|
||||||
if err != nil {
|
|
||||||
errlog := fmt.Sprintf("Cassandra服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
|
||||||
Common.LogError(errlog)
|
|
||||||
|
|
||||||
// 检查是否需要重试
|
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
|
||||||
if retryCount == maxRetries-1 {
|
|
||||||
resultChan <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
continue // 继续重试
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break // 如果不需要重试,跳出重试循环
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
resultChan <- nil
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 等待所有线程完成
|
// 处理错误情况
|
||||||
go func() {
|
if err != nil {
|
||||||
wg.Wait()
|
errlog := fmt.Sprintf("Cassandra服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
||||||
close(resultChan)
|
info.Host, info.Ports, user, pass, err)
|
||||||
}()
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查结果
|
// 检查是否需要重试
|
||||||
for err := range resultChan {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if err != nil {
|
if retryCount == maxRetries-1 {
|
||||||
tmperr = err
|
return err
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
}
|
||||||
return err
|
continue // 继续重试
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break // 如果不需要重试,跳出重试循环
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -541,7 +541,7 @@ func (d *DomainInfo) GetSPNs() (map[string][]string, error) {
|
|||||||
_ = entry.GetAttributeValue("cn")
|
_ = entry.GetAttributeValue("cn")
|
||||||
spnList := entry.GetAttributeValues("servicePrincipalName")
|
spnList := entry.GetAttributeValues("servicePrincipalName")
|
||||||
if len(spnList) > 0 {
|
if len(spnList) > 0 {
|
||||||
key := fmt.Sprintf("[*] SPN:%s", dn)
|
key := fmt.Sprintf("SPN:%s", dn)
|
||||||
spns[key] = spnList
|
spns[key] = spnList
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -708,7 +708,7 @@ func DCInfoScan(info *Common.HostInfo) (err error) {
|
|||||||
|
|
||||||
for _, category := range categories {
|
for _, category := range categories {
|
||||||
if computers, ok := specialComputers[category]; ok {
|
if computers, ok := specialComputers[category]; ok {
|
||||||
fmt.Printf("[*] %s:\n", category)
|
fmt.Printf("%s:\n", category)
|
||||||
for _, computer := range computers {
|
for _, computer := range computers {
|
||||||
fmt.Printf("\t%s\n", computer)
|
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 {
|
for _, user := range users {
|
||||||
fmt.Println("\t" + user)
|
fmt.Println("\t" + user)
|
||||||
}
|
}
|
||||||
@ -737,7 +737,7 @@ func DCInfoScan(info *Common.HostInfo) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 打印域管理员信息
|
// 打印域管理员信息
|
||||||
fmt.Println("[*] 域管理员:")
|
fmt.Println("域管理员:")
|
||||||
for _, admin := range admins {
|
for _, admin := range admins {
|
||||||
fmt.Println("\t" + admin)
|
fmt.Println("\t" + admin)
|
||||||
}
|
}
|
||||||
@ -750,7 +750,7 @@ func DCInfoScan(info *Common.HostInfo) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 打印组织单位信息
|
// 打印组织单位信息
|
||||||
fmt.Println("[*] 组织单位:")
|
fmt.Println("组织单位:")
|
||||||
for _, ou := range ous {
|
for _, ou := range ous {
|
||||||
fmt.Println("\t" + ou)
|
fmt.Println("\t" + ou)
|
||||||
}
|
}
|
||||||
@ -763,7 +763,7 @@ func DCInfoScan(info *Common.HostInfo) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 打印域计算机信息
|
// 打印域计算机信息
|
||||||
fmt.Println("[*] 域计算机:")
|
fmt.Println("域计算机:")
|
||||||
for _, computer := range computers {
|
for _, computer := range computers {
|
||||||
fmt.Printf("\t%s", computer.Name)
|
fmt.Printf("\t%s", computer.Name)
|
||||||
if computer.OperatingSystem != "" {
|
if computer.OperatingSystem != "" {
|
||||||
@ -775,7 +775,7 @@ func DCInfoScan(info *Common.HostInfo) (err error) {
|
|||||||
// 获取并显示信任域关系
|
// 获取并显示信任域关系
|
||||||
trustDomains, err := di.GetTrustDomains()
|
trustDomains, err := di.GetTrustDomains()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
fmt.Println("[*] 信任域关系:")
|
fmt.Println("信任域关系:")
|
||||||
for _, domain := range trustDomains {
|
for _, domain := range trustDomains {
|
||||||
fmt.Printf("\t%s\n", domain)
|
fmt.Printf("\t%s\n", domain)
|
||||||
}
|
}
|
||||||
@ -786,7 +786,7 @@ func DCInfoScan(info *Common.HostInfo) (err error) {
|
|||||||
adminGroups, err := di.GetAdminGroups()
|
adminGroups, err := di.GetAdminGroups()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
for groupName, members := range adminGroups {
|
for groupName, members := range adminGroups {
|
||||||
fmt.Printf("[*] %s成员:\n", groupName)
|
fmt.Printf("%s成员:\n", groupName)
|
||||||
for _, member := range members {
|
for _, member := range members {
|
||||||
fmt.Printf("\t%s\n", member)
|
fmt.Printf("\t%s\n", member)
|
||||||
}
|
}
|
||||||
@ -798,7 +798,7 @@ func DCInfoScan(info *Common.HostInfo) (err error) {
|
|||||||
delegations, err := di.GetDelegation()
|
delegations, err := di.GetDelegation()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
for delegationType, entries := range delegations {
|
for delegationType, entries := range delegations {
|
||||||
fmt.Printf("[*] %s:\n", delegationType)
|
fmt.Printf("%s:\n", delegationType)
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
fmt.Printf("\t%s\n", entry)
|
fmt.Printf("\t%s\n", entry)
|
||||||
}
|
}
|
||||||
@ -809,7 +809,7 @@ func DCInfoScan(info *Common.HostInfo) (err error) {
|
|||||||
// 获取并显示AS-REP Roasting漏洞用户
|
// 获取并显示AS-REP Roasting漏洞用户
|
||||||
asrepUsers, err := di.GetAsrepRoastUsers()
|
asrepUsers, err := di.GetAsrepRoastUsers()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
fmt.Println("[*] AS-REP弱口令账户:")
|
fmt.Println("AS-REP弱口令账户:")
|
||||||
for _, user := range asrepUsers {
|
for _, user := range asrepUsers {
|
||||||
fmt.Printf("\t%s\n", user)
|
fmt.Printf("\t%s\n", user)
|
||||||
}
|
}
|
||||||
@ -819,7 +819,7 @@ func DCInfoScan(info *Common.HostInfo) (err error) {
|
|||||||
// 获取并显示域密码策略
|
// 获取并显示域密码策略
|
||||||
passwordPolicy, err := di.GetPasswordPolicy()
|
passwordPolicy, err := di.GetPasswordPolicy()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
fmt.Println("[*] 域密码策略:")
|
fmt.Println("域密码策略:")
|
||||||
for key, value := range passwordPolicy {
|
for key, value := range passwordPolicy {
|
||||||
fmt.Printf("\t%s: %s\n", key, value)
|
fmt.Printf("\t%s: %s\n", key, value)
|
||||||
}
|
}
|
||||||
@ -843,7 +843,7 @@ func DCInfoScan(info *Common.HostInfo) (err error) {
|
|||||||
fmt.Println()
|
fmt.Println()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("[*] 未发现SPN信息\n")
|
fmt.Println("未发现SPN信息\n")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -18,7 +17,6 @@ func ElasticScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
maxRetries := Common.MaxRetries
|
maxRetries := Common.MaxRetries
|
||||||
threads := Common.BruteThreads
|
|
||||||
|
|
||||||
// 首先测试无认证访问
|
// 首先测试无认证访问
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
@ -35,105 +33,62 @@ func ElasticScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建任务通道
|
starttime := time.Now().Unix()
|
||||||
taskChan := make(chan struct {
|
|
||||||
user string
|
|
||||||
pass string
|
|
||||||
}, len(Common.Userdict["elastic"])*len(Common.Passwords))
|
|
||||||
|
|
||||||
resultChan := make(chan error, threads)
|
// 遍历所有用户名密码组合
|
||||||
|
|
||||||
// 生成所有用户名密码组合任务
|
|
||||||
for _, user := range Common.Userdict["elastic"] {
|
for _, user := range Common.Userdict["elastic"] {
|
||||||
for _, pass := range Common.Passwords {
|
for _, pass := range Common.Passwords {
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
pass = strings.Replace(pass, "{user}", user, -1)
|
||||||
taskChan <- struct {
|
|
||||||
user string
|
|
||||||
pass string
|
|
||||||
}{user, pass}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(taskChan)
|
|
||||||
|
|
||||||
// 启动工作线程
|
// 检查是否超时
|
||||||
var wg sync.WaitGroup
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
for i := 0; i < threads; i++ {
|
return fmt.Errorf("扫描超时")
|
||||||
wg.Add(1)
|
}
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
starttime := time.Now().Unix()
|
|
||||||
|
|
||||||
for task := range taskChan {
|
// 重试循环
|
||||||
// 重试循环
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
// 执行连接尝试
|
||||||
// 检查是否超时
|
done := make(chan struct {
|
||||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
success bool
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
err error
|
||||||
return
|
})
|
||||||
}
|
|
||||||
|
|
||||||
// 执行连接尝试
|
go func(user, pass string) {
|
||||||
done := make(chan struct {
|
flag, err := ElasticConn(info, user, pass)
|
||||||
|
done <- struct {
|
||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
})
|
}{flag, err}
|
||||||
|
}(user, pass)
|
||||||
|
|
||||||
go func(user, pass string) {
|
// 等待结果或超时
|
||||||
flag, err := ElasticConn(info, user, pass)
|
var err error
|
||||||
done <- struct {
|
select {
|
||||||
success bool
|
case result := <-done:
|
||||||
err error
|
err = result.err
|
||||||
}{flag, err}
|
if result.success && err == nil {
|
||||||
}(task.user, task.pass)
|
return nil
|
||||||
|
|
||||||
// 等待结果或超时
|
|
||||||
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("连接超时")
|
|
||||||
}
|
}
|
||||||
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
// 处理错误情况
|
err = fmt.Errorf("连接超时")
|
||||||
if err != nil {
|
|
||||||
errlog := fmt.Sprintf("Elasticsearch服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
|
||||||
Common.LogError(errlog)
|
|
||||||
|
|
||||||
// 检查是否需要重试
|
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
|
||||||
if retryCount == maxRetries-1 {
|
|
||||||
resultChan <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
continue // 继续重试
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break // 如果不需要重试,跳出重试循环
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
resultChan <- nil
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 等待所有线程完成
|
// 处理错误情况
|
||||||
go func() {
|
if err != nil {
|
||||||
wg.Wait()
|
errlog := fmt.Sprintf("Elasticsearch服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
||||||
close(resultChan)
|
info.Host, info.Ports, user, pass, err)
|
||||||
}()
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查结果
|
// 检查是否需要重试
|
||||||
for err := range resultChan {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if err != nil {
|
if retryCount == maxRetries-1 {
|
||||||
tmperr = err
|
return err
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
}
|
||||||
return err
|
continue // 继续重试
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break // 如果不需要重试,跳出重试循环
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
188
Plugins/FTP.go
188
Plugins/FTP.go
@ -1,12 +1,10 @@
|
|||||||
package Plugins
|
package Plugins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/jlaffaye/ftp"
|
"github.com/jlaffaye/ftp"
|
||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -17,11 +15,6 @@ func FtpScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
maxRetries := Common.MaxRetries
|
maxRetries := Common.MaxRetries
|
||||||
threads := Common.BruteThreads
|
|
||||||
|
|
||||||
// 创建带取消功能的context
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
// 先尝试匿名登录
|
// 先尝试匿名登录
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
@ -29,152 +22,74 @@ func FtpScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
if flag && err == nil {
|
if flag && err == nil {
|
||||||
return 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)
|
Common.LogError(errlog)
|
||||||
|
|
||||||
if err != nil && !strings.Contains(err.Error(), "Login incorrect") {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
if retryCount == maxRetries-1 {
|
||||||
if retryCount == maxRetries-1 {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
taskChan := make(chan struct {
|
starttime := time.Now().Unix()
|
||||||
user string
|
|
||||||
pass string
|
|
||||||
}, len(Common.Userdict["ftp"])*len(Common.Passwords))
|
|
||||||
|
|
||||||
// 任务分发goroutine
|
// 遍历所有用户名密码组合
|
||||||
go func() {
|
for _, user := range Common.Userdict["ftp"] {
|
||||||
defer close(taskChan)
|
for _, pass := range Common.Passwords {
|
||||||
for _, user := range Common.Userdict["ftp"] {
|
pass = strings.Replace(pass, "{user}", user, -1)
|
||||||
for _, pass := range Common.Passwords {
|
|
||||||
select {
|
// 检查是否超时
|
||||||
case <-ctx.Done():
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
return
|
return fmt.Errorf("扫描超时")
|
||||||
default:
|
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
|
||||||
taskChan <- struct {
|
|
||||||
user string
|
|
||||||
pass string
|
|
||||||
}{user, pass}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
// 重试循环
|
||||||
resultChan := make(chan error, threads)
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
|
// 执行FTP连接
|
||||||
|
done := make(chan struct {
|
||||||
|
success bool
|
||||||
|
err error
|
||||||
|
})
|
||||||
|
|
||||||
// 启动工作线程
|
go func(user, pass string) {
|
||||||
for i := 0; i < threads; i++ {
|
success, err := FtpConn(info, user, pass)
|
||||||
wg.Add(1)
|
done <- struct {
|
||||||
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 {
|
|
||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
}, 1)
|
}{success, err}
|
||||||
|
}(user, pass)
|
||||||
|
|
||||||
connCtx, connCancel := context.WithTimeout(ctx, time.Duration(Common.Timeout)*time.Second)
|
// 等待结果或超时
|
||||||
|
var err error
|
||||||
go func(user, pass string) {
|
select {
|
||||||
success, err := FtpConn(info, user, pass)
|
case result := <-done:
|
||||||
select {
|
err = result.err
|
||||||
case <-connCtx.Done():
|
if result.success && err == nil {
|
||||||
case done <- struct {
|
return nil
|
||||||
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("连接超时")
|
|
||||||
}
|
}
|
||||||
|
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 {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
case <-ctx.Done():
|
if retryCount == maxRetries-1 {
|
||||||
resultChan <- nil
|
return err
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
continue // 继续重试
|
||||||
}
|
}
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
resultChan <- nil
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
break // 如果不需要重试,跳出重试循环
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -191,12 +106,6 @@ func FtpConn(info *Common.HostInfo, user string, pass string) (flag bool, err er
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
// 确保连接被关闭
|
|
||||||
defer func() {
|
|
||||||
if conn != nil {
|
|
||||||
conn.Quit() // 发送QUIT命令关闭连接
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// 尝试登录
|
// 尝试登录
|
||||||
if err = conn.Login(Username, Password); err != nil {
|
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("")
|
dirs, err := conn.List("")
|
||||||
if err == nil && len(dirs) > 0 {
|
if err == nil && len(dirs) > 0 {
|
||||||
// 最多显示前6个目录
|
// 最多显示前6个目录
|
||||||
@ -217,5 +126,6 @@ func FtpConn(info *Common.HostInfo, user string, pass string) (flag bool, err er
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Common.LogSuccess(result)
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
@ -71,14 +71,14 @@ func FcgiScan(info *Common.HostInfo) error {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
if err != nil {
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 发送FastCGI请求
|
// 发送FastCGI请求
|
||||||
stdout, stderr, err := fcgi.Request(env, reqParams)
|
stdout, stderr, err := fcgi.Request(env, reqParams)
|
||||||
if err != nil {
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,10 +90,10 @@ func FcgiScan(info *Common.HostInfo) error {
|
|||||||
// 命令执行成功,提取输出结果
|
// 命令执行成功,提取输出结果
|
||||||
output = strings.SplitN(output, cutLine, 2)[0]
|
output = strings.SplitN(output, cutLine, 2)[0]
|
||||||
if len(stderr) > 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))
|
info.Host, info.Ports, output, string(stderr))
|
||||||
} else {
|
} else {
|
||||||
result = fmt.Sprintf("[+] FastCGI漏洞确认 %v:%v\n命令输出:\n%v",
|
result = fmt.Sprintf("FastCGI漏洞确认 %v:%v\n命令输出:\n%v",
|
||||||
info.Host, info.Ports, output)
|
info.Host, info.Ports, output)
|
||||||
}
|
}
|
||||||
Common.LogSuccess(result)
|
Common.LogSuccess(result)
|
||||||
@ -102,10 +102,10 @@ func FcgiScan(info *Common.HostInfo) error {
|
|||||||
strings.Contains(output, "Status") {
|
strings.Contains(output, "Status") {
|
||||||
// 目标存在FastCGI服务但可能路径错误
|
// 目标存在FastCGI服务但可能路径错误
|
||||||
if len(stderr) > 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))
|
info.Host, info.Ports, output, string(stderr))
|
||||||
} else {
|
} else {
|
||||||
result = fmt.Sprintf("[*] FastCGI服务确认 %v:%v\n响应:\n%v",
|
result = fmt.Sprintf("FastCGI服务确认 %v:%v\n响应:\n%v",
|
||||||
info.Host, info.Ports, output)
|
info.Host, info.Ports, output)
|
||||||
}
|
}
|
||||||
Common.LogSuccess(result)
|
Common.LogSuccess(result)
|
||||||
|
@ -149,12 +149,12 @@ func read(text []byte, host string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 构建基础结果
|
// 构建基础结果
|
||||||
result := fmt.Sprintf("[*] NetInfo 扫描结果")
|
result := fmt.Sprintf("NetInfo 扫描结果")
|
||||||
result += fmt.Sprintf("\n[*] 目标主机: %s", host)
|
result += fmt.Sprintf("\n目标主机: %s", host)
|
||||||
if name != "" {
|
if name != "" {
|
||||||
result += fmt.Sprintf("\n[*] 主机名: %s", name)
|
result += fmt.Sprintf("\n主机名: %s", name)
|
||||||
}
|
}
|
||||||
result += "\n[*] 发现的网络接口:"
|
result += "\n发现的网络接口:"
|
||||||
|
|
||||||
// 用于分类存储地址
|
// 用于分类存储地址
|
||||||
var ipv4Addrs []string
|
var ipv4Addrs []string
|
||||||
|
124
Plugins/IMAP.go
124
Plugins/IMAP.go
@ -8,7 +8,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -18,102 +17,61 @@ func IMAPScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
maxRetries := Common.MaxRetries
|
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 _, user := range Common.Userdict["imap"] {
|
||||||
for _, pass := range Common.Passwords {
|
for _, pass := range Common.Passwords {
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
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++ {
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
wg.Add(1)
|
return fmt.Errorf("扫描超时")
|
||||||
go func() {
|
}
|
||||||
defer wg.Done()
|
|
||||||
starttime := time.Now().Unix()
|
|
||||||
|
|
||||||
for task := range taskChan {
|
// 重试循环
|
||||||
// 重试循环
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
// 执行IMAP连接
|
||||||
// 检查是否超时
|
done := make(chan struct {
|
||||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
success bool
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
err error
|
||||||
return
|
})
|
||||||
}
|
|
||||||
|
|
||||||
// 执行IMAP连接
|
go func(user, pass string) {
|
||||||
done := make(chan struct {
|
success, err := IMAPConn(info, user, pass)
|
||||||
|
done <- struct {
|
||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
})
|
}{success, err}
|
||||||
|
}(user, pass)
|
||||||
|
|
||||||
go func(user, pass string) {
|
// 等待结果或超时
|
||||||
success, err := IMAPConn(info, user, pass)
|
var err error
|
||||||
done <- struct {
|
select {
|
||||||
success bool
|
case result := <-done:
|
||||||
err error
|
err = result.err
|
||||||
}{success, err}
|
if result.success && err == nil {
|
||||||
}(task.user, task.pass)
|
return nil
|
||||||
|
|
||||||
// 等待结果或超时
|
|
||||||
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("连接超时")
|
|
||||||
}
|
}
|
||||||
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
// 处理错误情况
|
err = fmt.Errorf("连接超时")
|
||||||
if err != nil {
|
|
||||||
errlog := fmt.Sprintf("IMAP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
|
||||||
Common.LogError(errlog)
|
|
||||||
|
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
|
||||||
if retryCount == maxRetries-1 {
|
|
||||||
resultChan <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
resultChan <- nil
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
// 处理错误情况
|
||||||
wg.Wait()
|
if err != nil {
|
||||||
close(resultChan)
|
errlog := fmt.Sprintf("IMAP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
||||||
}()
|
info.Host, info.Ports, user, pass, err)
|
||||||
|
Common.LogError(errlog)
|
||||||
|
|
||||||
for err := range resultChan {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if err != nil {
|
if retryCount == maxRetries-1 {
|
||||||
tmperr = err
|
return err
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
}
|
||||||
return err
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
130
Plugins/Kafka.go
130
Plugins/Kafka.go
@ -5,18 +5,15 @@ import (
|
|||||||
"github.com/IBM/sarama"
|
"github.com/IBM/sarama"
|
||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// KafkaScan 执行 Kafka 服务扫描
|
|
||||||
func KafkaScan(info *Common.HostInfo) (tmperr error) {
|
func KafkaScan(info *Common.HostInfo) (tmperr error) {
|
||||||
if Common.DisableBrute {
|
if Common.DisableBrute {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
maxRetries := Common.MaxRetries
|
maxRetries := Common.MaxRetries
|
||||||
threads := Common.BruteThreads
|
|
||||||
|
|
||||||
// 首先测试无认证访问
|
// 首先测试无认证访问
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
@ -33,105 +30,62 @@ func KafkaScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建任务通道
|
starttime := time.Now().Unix()
|
||||||
taskChan := make(chan struct {
|
|
||||||
user string
|
|
||||||
pass string
|
|
||||||
}, len(Common.Userdict["kafka"])*len(Common.Passwords))
|
|
||||||
|
|
||||||
resultChan := make(chan error, threads)
|
// 遍历所有用户名密码组合
|
||||||
|
|
||||||
// 生成所有用户名密码组合任务
|
|
||||||
for _, user := range Common.Userdict["kafka"] {
|
for _, user := range Common.Userdict["kafka"] {
|
||||||
for _, pass := range Common.Passwords {
|
for _, pass := range Common.Passwords {
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
pass = strings.Replace(pass, "{user}", user, -1)
|
||||||
taskChan <- struct {
|
|
||||||
user string
|
|
||||||
pass string
|
|
||||||
}{user, pass}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(taskChan)
|
|
||||||
|
|
||||||
// 启动工作线程
|
// 检查是否超时
|
||||||
var wg sync.WaitGroup
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
for i := 0; i < threads; i++ {
|
return fmt.Errorf("扫描超时")
|
||||||
wg.Add(1)
|
}
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
starttime := time.Now().Unix()
|
|
||||||
|
|
||||||
for task := range taskChan {
|
// 重试循环
|
||||||
// 重试循环
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
// 执行Kafka连接
|
||||||
// 检查是否超时
|
done := make(chan struct {
|
||||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
success bool
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
err error
|
||||||
return
|
})
|
||||||
}
|
|
||||||
|
|
||||||
// 执行Kafka连接
|
go func(user, pass string) {
|
||||||
done := make(chan struct {
|
success, err := KafkaConn(info, user, pass)
|
||||||
|
done <- struct {
|
||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
})
|
}{success, err}
|
||||||
|
}(user, pass)
|
||||||
|
|
||||||
go func(user, pass string) {
|
// 等待结果或超时
|
||||||
success, err := KafkaConn(info, user, pass)
|
var err error
|
||||||
done <- struct {
|
select {
|
||||||
success bool
|
case result := <-done:
|
||||||
err error
|
err = result.err
|
||||||
}{success, err}
|
if result.success && err == nil {
|
||||||
}(task.user, task.pass)
|
return nil
|
||||||
|
|
||||||
// 等待结果或超时
|
|
||||||
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("连接超时")
|
|
||||||
}
|
}
|
||||||
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
// 处理错误情况
|
err = fmt.Errorf("连接超时")
|
||||||
if err != nil {
|
|
||||||
errlog := fmt.Sprintf("Kafka服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
|
||||||
Common.LogError(errlog)
|
|
||||||
|
|
||||||
// 检查是否需要重试
|
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
|
||||||
if retryCount == maxRetries-1 {
|
|
||||||
resultChan <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
continue // 继续重试
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break // 如果不需要重试,跳出重试循环
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
resultChan <- nil
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 等待所有线程完成
|
// 处理错误情况
|
||||||
go func() {
|
if err != nil {
|
||||||
wg.Wait()
|
errlog := fmt.Sprintf("Kafka服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
||||||
close(resultChan)
|
info.Host, info.Ports, user, pass, err)
|
||||||
}()
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查结果
|
// 检查是否需要重试
|
||||||
for err := range resultChan {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if err != nil {
|
if retryCount == maxRetries-1 {
|
||||||
tmperr = err
|
return err
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
}
|
||||||
return err
|
continue // 继续重试
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break // 如果不需要重试,跳出重试循环
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
129
Plugins/LDAP.go
129
Plugins/LDAP.go
@ -5,7 +5,6 @@ import (
|
|||||||
"github.com/go-ldap/ldap/v3"
|
"github.com/go-ldap/ldap/v3"
|
||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -16,7 +15,6 @@ func LDAPScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
maxRetries := Common.MaxRetries
|
maxRetries := Common.MaxRetries
|
||||||
threads := Common.BruteThreads
|
|
||||||
|
|
||||||
// 首先尝试匿名访问
|
// 首先尝试匿名访问
|
||||||
flag, err := LDAPConn(info, "", "")
|
flag, err := LDAPConn(info, "", "")
|
||||||
@ -24,105 +22,62 @@ func LDAPScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建任务通道
|
starttime := time.Now().Unix()
|
||||||
taskChan := make(chan struct {
|
|
||||||
user string
|
|
||||||
pass string
|
|
||||||
}, len(Common.Userdict["ldap"])*len(Common.Passwords))
|
|
||||||
|
|
||||||
resultChan := make(chan error, threads)
|
// 遍历所有用户名密码组合
|
||||||
|
|
||||||
// 生成所有用户名密码组合任务
|
|
||||||
for _, user := range Common.Userdict["ldap"] {
|
for _, user := range Common.Userdict["ldap"] {
|
||||||
for _, pass := range Common.Passwords {
|
for _, pass := range Common.Passwords {
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
pass = strings.Replace(pass, "{user}", user, -1)
|
||||||
taskChan <- struct {
|
|
||||||
user string
|
|
||||||
pass string
|
|
||||||
}{user, pass}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(taskChan)
|
|
||||||
|
|
||||||
// 启动工作线程
|
// 检查是否超时
|
||||||
var wg sync.WaitGroup
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
for i := 0; i < threads; i++ {
|
return fmt.Errorf("扫描超时")
|
||||||
wg.Add(1)
|
}
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
starttime := time.Now().Unix()
|
|
||||||
|
|
||||||
for task := range taskChan {
|
// 重试循环
|
||||||
// 重试循环
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
// 执行LDAP连接
|
||||||
// 检查是否超时
|
done := make(chan struct {
|
||||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
success bool
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
err error
|
||||||
return
|
})
|
||||||
}
|
|
||||||
|
|
||||||
// 执行LDAP连接
|
go func(user, pass string) {
|
||||||
done := make(chan struct {
|
success, err := LDAPConn(info, user, pass)
|
||||||
|
done <- struct {
|
||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
})
|
}{success, err}
|
||||||
|
}(user, pass)
|
||||||
|
|
||||||
go func(user, pass string) {
|
// 等待结果或超时
|
||||||
success, err := LDAPConn(info, user, pass)
|
var err error
|
||||||
done <- struct {
|
select {
|
||||||
success bool
|
case result := <-done:
|
||||||
err error
|
err = result.err
|
||||||
}{success, err}
|
if result.success && err == nil {
|
||||||
}(task.user, task.pass)
|
return nil
|
||||||
|
|
||||||
// 等待结果或超时
|
|
||||||
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("连接超时")
|
|
||||||
}
|
}
|
||||||
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
// 处理错误情况
|
err = fmt.Errorf("连接超时")
|
||||||
if err != nil {
|
|
||||||
errlog := fmt.Sprintf("LDAP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
|
||||||
Common.LogError(errlog)
|
|
||||||
|
|
||||||
// 检查是否需要重试
|
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
|
||||||
if retryCount == maxRetries-1 {
|
|
||||||
resultChan <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
continue // 继续重试
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break // 如果不需要重试,跳出重试循环
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
resultChan <- nil
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 等待所有线程完成
|
// 处理错误情况
|
||||||
go func() {
|
if err != nil {
|
||||||
wg.Wait()
|
errlog := fmt.Sprintf("LDAP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
||||||
close(resultChan)
|
info.Host, info.Ports, user, pass, err)
|
||||||
}()
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查结果
|
// 检查是否需要重试
|
||||||
for err := range resultChan {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if err != nil {
|
if retryCount == maxRetries-1 {
|
||||||
tmperr = err
|
return err
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
}
|
||||||
return err
|
continue // 继续重试
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break // 如果不需要重试,跳出重试循环
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,10 +89,10 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func LocalInfoScan(info *Common.HostInfo) (err error) {
|
func LocalInfoScan(info *Common.HostInfo) (err error) {
|
||||||
fmt.Println("[+] LocalInfo扫描模块开始...")
|
fmt.Println("LocalInfo扫描模块开始...")
|
||||||
home, err := os.UserHomeDir()
|
home, err := os.UserHomeDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errlog := fmt.Sprintf("[-] Get UserHomeDir error: %v", err)
|
errlog := fmt.Sprintf("Get UserHomeDir error: %v", err)
|
||||||
Common.LogError(errlog)
|
Common.LogError(errlog)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -103,7 +103,7 @@ func LocalInfoScan(info *Common.HostInfo) (err error) {
|
|||||||
// 规则搜索
|
// 规则搜索
|
||||||
searchSensitiveFiles()
|
searchSensitiveFiles()
|
||||||
|
|
||||||
fmt.Println("[+] LocalInfo扫描模块结束...")
|
fmt.Println("LocalInfo扫描模块结束...")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,7 +148,7 @@ func scanFixedLocations(home string) {
|
|||||||
|
|
||||||
func checkAndLogFile(path string) {
|
func checkAndLogFile(path string) {
|
||||||
if _, err := os.Stat(path); err == nil {
|
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)
|
Common.LogSuccess(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -202,7 +202,7 @@ func searchSensitiveFiles() {
|
|||||||
for _, white := range whitelist {
|
for _, white := range whitelist {
|
||||||
fileName := strings.ToLower(info.Name())
|
fileName := strings.ToLower(info.Name())
|
||||||
if strings.Contains(fileName, white) {
|
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)
|
Common.LogSuccess(result)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
127
Plugins/MSSQL.go
127
Plugins/MSSQL.go
@ -6,7 +6,6 @@ import (
|
|||||||
_ "github.com/denisenkom/go-mssqldb"
|
_ "github.com/denisenkom/go-mssqldb"
|
||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -17,103 +16,61 @@ func MssqlScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
maxRetries := Common.MaxRetries
|
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 _, user := range Common.Userdict["mssql"] {
|
||||||
for _, pass := range Common.Passwords {
|
for _, pass := range Common.Passwords {
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
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++ {
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
wg.Add(1)
|
return fmt.Errorf("扫描超时")
|
||||||
go func() {
|
}
|
||||||
defer wg.Done()
|
|
||||||
starttime := time.Now().Unix()
|
|
||||||
|
|
||||||
for task := range taskChan {
|
// 重试循环
|
||||||
// 重试循环
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
// 执行MSSQL连接
|
||||||
// 检查是否超时
|
done := make(chan struct {
|
||||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
success bool
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
err error
|
||||||
return
|
})
|
||||||
}
|
|
||||||
|
|
||||||
// 执行MSSQL连接
|
go func(user, pass string) {
|
||||||
done := make(chan struct {
|
success, err := MssqlConn(info, user, pass)
|
||||||
|
done <- struct {
|
||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
})
|
}{success, err}
|
||||||
|
}(user, pass)
|
||||||
|
|
||||||
go func(user, pass string) {
|
// 等待结果或超时
|
||||||
success, err := MssqlConn(info, user, pass)
|
var err error
|
||||||
done <- struct {
|
select {
|
||||||
success bool
|
case result := <-done:
|
||||||
err error
|
err = result.err
|
||||||
}{success, err}
|
if result.success && err == nil {
|
||||||
}(task.user, task.pass)
|
return nil
|
||||||
|
|
||||||
// 等待结果或超时
|
|
||||||
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("连接超时")
|
|
||||||
}
|
}
|
||||||
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
if err != nil {
|
err = fmt.Errorf("连接超时")
|
||||||
errlog := fmt.Sprintf("MSSQL %v:%v %v %v %v",
|
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
|
||||||
Common.LogError(errlog)
|
|
||||||
|
|
||||||
// 检查是否需要重试
|
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
|
||||||
if retryCount == maxRetries-1 {
|
|
||||||
resultChan <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
continue // 继续重试
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break // 如果不需要重试,跳出重试循环
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
resultChan <- nil
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
if err != nil {
|
||||||
wg.Wait()
|
errlog := fmt.Sprintf("MSSQL %v:%v %v %v %v",
|
||||||
close(resultChan)
|
info.Host, info.Ports, user, pass, err)
|
||||||
}()
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查结果
|
// 检查是否需要重试
|
||||||
for err := range resultChan {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if err != nil {
|
if retryCount == maxRetries-1 {
|
||||||
tmperr = err
|
return err
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
}
|
||||||
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)
|
Common.LogSuccess(result)
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
165
Plugins/MySQL.go
165
Plugins/MySQL.go
@ -6,7 +6,6 @@ import (
|
|||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -17,132 +16,72 @@ func MysqlScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
maxRetries := Common.MaxRetries
|
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 _, user := range Common.Userdict["mysql"] {
|
||||||
for _, pass := range Common.Passwords {
|
for _, pass := range Common.Passwords {
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
pass = strings.Replace(pass, "{user}", user, -1)
|
||||||
taskChan <- struct {
|
|
||||||
user string
|
|
||||||
pass string
|
|
||||||
}{user, pass}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(taskChan)
|
|
||||||
|
|
||||||
// 启动工作线程
|
// 检查是否超时
|
||||||
var wg sync.WaitGroup
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
for i := 0; i < threads; i++ {
|
return fmt.Errorf("扫描超时")
|
||||||
wg.Add(1)
|
}
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
starttime := time.Now().Unix()
|
|
||||||
|
|
||||||
for task := range taskChan {
|
// 重试循环
|
||||||
// 检查是否已经成功
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
select {
|
// 执行MySQL连接
|
||||||
case <-successChan:
|
done := make(chan struct {
|
||||||
resultChan <- nil
|
success bool
|
||||||
return
|
err error
|
||||||
default:
|
})
|
||||||
}
|
|
||||||
|
|
||||||
// 重试循环
|
go func(user, pass string) {
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
success, err := MysqlConn(info, user, pass)
|
||||||
// 检查是否超时
|
done <- struct {
|
||||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 执行MySQL连接
|
|
||||||
done := make(chan struct {
|
|
||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
})
|
}{success, err}
|
||||||
|
}(user, pass)
|
||||||
|
|
||||||
go func(user, pass string) {
|
// 等待结果或超时
|
||||||
success, err := MysqlConn(info, user, pass)
|
var err error
|
||||||
done <- struct {
|
select {
|
||||||
success bool
|
case result := <-done:
|
||||||
err error
|
err = result.err
|
||||||
}{success, err}
|
if result.success && err == nil {
|
||||||
}(task.user, task.pass)
|
// 连接成功
|
||||||
|
successLog := fmt.Sprintf("MySQL %v:%v %v %v",
|
||||||
// 等待结果或超时
|
info.Host, info.Ports, user, pass)
|
||||||
var err error
|
Common.LogSuccess(successLog)
|
||||||
select {
|
return nil
|
||||||
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 // 如果不需要重试,跳出重试循环
|
|
||||||
}
|
}
|
||||||
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
|
err = fmt.Errorf("连接超时")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
resultChan <- nil
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 等待所有线程完成
|
// 处理错误情况
|
||||||
go func() {
|
if err != nil {
|
||||||
wg.Wait()
|
errlog := fmt.Sprintf("MySQL %v:%v %v %v %v",
|
||||||
close(resultChan)
|
info.Host, info.Ports, user, pass, err)
|
||||||
}()
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查结果
|
// 特殊处理认证失败的情况
|
||||||
for err := range resultChan {
|
if strings.Contains(err.Error(), "Access denied") {
|
||||||
if err != nil {
|
break // 跳出重试循环,继续下一个密码
|
||||||
tmperr = err
|
}
|
||||||
if !strings.Contains(err.Error(), "Access denied") {
|
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
// 检查是否需要重试
|
||||||
return err
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
|
if retryCount == maxRetries-1 {
|
||||||
|
tmperr = err
|
||||||
|
if !strings.Contains(err.Error(), "Access denied") {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue // 继续重试
|
||||||
|
}
|
||||||
|
break // 如果不需要重试,跳出重试循环
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
129
Plugins/Neo4j.go
129
Plugins/Neo4j.go
@ -5,7 +5,6 @@ import (
|
|||||||
"github.com/neo4j/neo4j-go-driver/v4/neo4j"
|
"github.com/neo4j/neo4j-go-driver/v4/neo4j"
|
||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -16,7 +15,6 @@ func Neo4jScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
maxRetries := Common.MaxRetries
|
maxRetries := Common.MaxRetries
|
||||||
threads := Common.BruteThreads
|
|
||||||
|
|
||||||
// 首先测试无认证访问和默认凭证
|
// 首先测试无认证访问和默认凭证
|
||||||
initialChecks := []struct {
|
initialChecks := []struct {
|
||||||
@ -34,105 +32,62 @@ func Neo4jScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建任务通道
|
starttime := time.Now().Unix()
|
||||||
taskChan := make(chan struct {
|
|
||||||
user string
|
|
||||||
pass string
|
|
||||||
}, len(Common.Userdict["neo4j"])*len(Common.Passwords))
|
|
||||||
|
|
||||||
resultChan := make(chan error, threads)
|
// 遍历所有用户名密码组合
|
||||||
|
|
||||||
// 生成所有用户名密码组合任务
|
|
||||||
for _, user := range Common.Userdict["neo4j"] {
|
for _, user := range Common.Userdict["neo4j"] {
|
||||||
for _, pass := range Common.Passwords {
|
for _, pass := range Common.Passwords {
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
pass = strings.Replace(pass, "{user}", user, -1)
|
||||||
taskChan <- struct {
|
|
||||||
user string
|
|
||||||
pass string
|
|
||||||
}{user, pass}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(taskChan)
|
|
||||||
|
|
||||||
// 启动工作线程
|
// 检查是否超时
|
||||||
var wg sync.WaitGroup
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
for i := 0; i < threads; i++ {
|
return fmt.Errorf("扫描超时")
|
||||||
wg.Add(1)
|
}
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
starttime := time.Now().Unix()
|
|
||||||
|
|
||||||
for task := range taskChan {
|
// 重试循环
|
||||||
// 重试循环
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
// 执行Neo4j连接
|
||||||
// 检查是否超时
|
done := make(chan struct {
|
||||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
success bool
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
err error
|
||||||
return
|
})
|
||||||
}
|
|
||||||
|
|
||||||
// 执行Neo4j连接
|
go func(user, pass string) {
|
||||||
done := make(chan struct {
|
flag, err := Neo4jConn(info, user, pass)
|
||||||
|
done <- struct {
|
||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
})
|
}{flag, err}
|
||||||
|
}(user, pass)
|
||||||
|
|
||||||
go func(user, pass string) {
|
// 等待结果或超时
|
||||||
flag, err := Neo4jConn(info, user, pass)
|
var err error
|
||||||
done <- struct {
|
select {
|
||||||
success bool
|
case result := <-done:
|
||||||
err error
|
err = result.err
|
||||||
}{flag, err}
|
if result.success && err == nil {
|
||||||
}(task.user, task.pass)
|
return nil
|
||||||
|
|
||||||
// 等待结果或超时
|
|
||||||
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("连接超时")
|
|
||||||
}
|
}
|
||||||
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
// 处理错误情况
|
err = fmt.Errorf("连接超时")
|
||||||
if err != nil {
|
|
||||||
errlog := fmt.Sprintf("Neo4j服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
|
||||||
Common.LogError(errlog)
|
|
||||||
|
|
||||||
// 检查是否需要重试
|
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
|
||||||
if retryCount == maxRetries-1 {
|
|
||||||
resultChan <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
continue // 继续重试
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break // 如果不需要重试,跳出重试循环
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
resultChan <- nil
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 等待所有线程完成
|
// 处理错误情况
|
||||||
go func() {
|
if err != nil {
|
||||||
wg.Wait()
|
errlog := fmt.Sprintf("Neo4j服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
||||||
close(resultChan)
|
info.Host, info.Ports, user, pass, err)
|
||||||
}()
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查结果
|
// 检查是否需要重试
|
||||||
for err := range resultChan {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if err != nil {
|
if retryCount == maxRetries-1 {
|
||||||
tmperr = err
|
return err
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
}
|
||||||
return err
|
continue // 继续重试
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break // 如果不需要重试,跳出重试循环
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -229,7 +229,7 @@ func (info *NetBiosInfo) String() (output string) {
|
|||||||
}
|
}
|
||||||
if text == "" {
|
if text == "" {
|
||||||
} else if info.DomainControllers != "" {
|
} else if info.DomainControllers != "" {
|
||||||
output = fmt.Sprintf("[+] DC:%-24s", text)
|
output = fmt.Sprintf("DC:%-24s", text)
|
||||||
} else {
|
} else {
|
||||||
output = fmt.Sprintf("%-30s", text)
|
output = fmt.Sprintf("%-30s", text)
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
_ "github.com/sijms/go-ora/v2"
|
_ "github.com/sijms/go-ora/v2"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -17,107 +16,62 @@ func OracleScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
maxRetries := Common.MaxRetries
|
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 _, user := range Common.Userdict["oracle"] {
|
||||||
for _, pass := range Common.Passwords {
|
for _, pass := range Common.Passwords {
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
pass = strings.Replace(pass, "{user}", user, -1)
|
||||||
taskChan <- struct {
|
|
||||||
user string
|
|
||||||
pass string
|
|
||||||
}{user, pass}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(taskChan)
|
|
||||||
|
|
||||||
// 启动工作线程
|
// 检查是否超时
|
||||||
var wg sync.WaitGroup
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
for i := 0; i < threads; i++ {
|
return fmt.Errorf("扫描超时")
|
||||||
wg.Add(1)
|
}
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
starttime := time.Now().Unix()
|
|
||||||
|
|
||||||
for task := range taskChan {
|
// 重试循环
|
||||||
// 重试循环
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
// 执行Oracle连接
|
||||||
// 检查是否超时
|
done := make(chan struct {
|
||||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
success bool
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
err error
|
||||||
return
|
})
|
||||||
}
|
|
||||||
|
|
||||||
// 执行Oracle连接
|
go func(user, pass string) {
|
||||||
done := make(chan struct {
|
success, err := OracleConn(info, user, pass)
|
||||||
|
done <- struct {
|
||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
})
|
}{success, err}
|
||||||
|
}(user, pass)
|
||||||
|
|
||||||
go func(user, pass string) {
|
// 等待结果或超时
|
||||||
success, err := OracleConn(info, user, pass)
|
var err error
|
||||||
done <- struct {
|
select {
|
||||||
success bool
|
case result := <-done:
|
||||||
err error
|
err = result.err
|
||||||
}{success, err}
|
if result.success && err == nil {
|
||||||
}(task.user, task.pass)
|
return nil
|
||||||
|
|
||||||
// 等待结果或超时
|
|
||||||
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("连接超时")
|
|
||||||
}
|
}
|
||||||
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
// 处理错误情况
|
err = fmt.Errorf("连接超时")
|
||||||
if err != nil {
|
|
||||||
errlog := fmt.Sprintf("Oracle %v:%v %v %v %v",
|
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
|
||||||
Common.LogError(errlog)
|
|
||||||
|
|
||||||
// 检查是否需要重试
|
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
|
||||||
if retryCount == maxRetries-1 {
|
|
||||||
resultChan <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
continue // 继续重试
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break // 如果不需要重试,跳出重试循环
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
resultChan <- nil
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 等待所有线程完成
|
// 处理错误情况
|
||||||
go func() {
|
if err != nil {
|
||||||
wg.Wait()
|
errlog := fmt.Sprintf("Oracle %v:%v %v %v %v",
|
||||||
close(resultChan)
|
info.Host, info.Ports, user, pass, err)
|
||||||
}()
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查结果
|
// 检查是否需要重试
|
||||||
for err := range resultChan {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if err != nil {
|
if retryCount == maxRetries-1 {
|
||||||
tmperr = err
|
return err
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
}
|
||||||
return err
|
continue // 继续重试
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break // 如果不需要重试,跳出重试循环
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
138
Plugins/POP3.go
138
Plugins/POP3.go
@ -7,7 +7,6 @@ import (
|
|||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -17,111 +16,66 @@ func POP3Scan(info *Common.HostInfo) (tmperr error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
maxRetries := Common.MaxRetries
|
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 _, user := range Common.Userdict["pop3"] {
|
||||||
for _, pass := range Common.Passwords {
|
for _, pass := range Common.Passwords {
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
pass = strings.Replace(pass, "{user}", user, -1)
|
||||||
taskChan <- struct {
|
|
||||||
user string
|
|
||||||
pass string
|
|
||||||
}{user, pass}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(taskChan)
|
|
||||||
|
|
||||||
// 启动工作线程
|
// 检查是否超时
|
||||||
var wg sync.WaitGroup
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
for i := 0; i < threads; i++ {
|
return fmt.Errorf("扫描超时")
|
||||||
wg.Add(1)
|
}
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
starttime := time.Now().Unix()
|
|
||||||
|
|
||||||
for task := range taskChan {
|
// 重试循环
|
||||||
// 重试循环
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
// 执行POP3连接
|
||||||
// 检查是否超时
|
done := make(chan struct {
|
||||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
success bool
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
err error
|
||||||
return
|
})
|
||||||
}
|
|
||||||
|
|
||||||
// 执行POP3连接
|
go func(user, pass string) {
|
||||||
done := make(chan struct {
|
success, err := POP3Conn(info, user, pass)
|
||||||
|
done <- struct {
|
||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
})
|
}{success, err}
|
||||||
|
}(user, pass)
|
||||||
|
|
||||||
go func(user, pass string) {
|
// 等待结果或超时
|
||||||
success, err := POP3Conn(info, user, pass)
|
var err error
|
||||||
done <- struct {
|
select {
|
||||||
success bool
|
case result := <-done:
|
||||||
err error
|
err = result.err
|
||||||
}{success, err}
|
if result.success && err == nil {
|
||||||
}(task.user, task.pass)
|
// 连接成功
|
||||||
|
successLog := fmt.Sprintf("POP3服务 %v:%v 用户名: %v 密码: %v",
|
||||||
// 等待结果或超时
|
info.Host, info.Ports, user, pass)
|
||||||
var err error
|
Common.LogSuccess(successLog)
|
||||||
select {
|
return nil
|
||||||
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("连接超时")
|
|
||||||
}
|
}
|
||||||
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
// 处理错误情况
|
err = fmt.Errorf("连接超时")
|
||||||
if err != nil {
|
|
||||||
errlog := fmt.Sprintf("POP3服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
|
||||||
Common.LogError(errlog)
|
|
||||||
|
|
||||||
// 检查是否需要重试
|
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
|
||||||
if retryCount == maxRetries-1 {
|
|
||||||
resultChan <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
continue // 继续重试
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break // 如果不需要重试,跳出重试循环
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
resultChan <- nil
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 等待所有线程完成
|
// 处理错误情况
|
||||||
go func() {
|
if err != nil {
|
||||||
wg.Wait()
|
errlog := fmt.Sprintf("POP3服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
||||||
close(resultChan)
|
info.Host, info.Ports, user, pass, err)
|
||||||
}()
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查结果
|
// 检查是否需要重试
|
||||||
for err := range resultChan {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if err != nil {
|
if retryCount == maxRetries-1 {
|
||||||
tmperr = err
|
return err
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
}
|
||||||
return err
|
continue // 继续重试
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break // 如果不需要重试,跳出重试循环
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -17,107 +16,62 @@ func PostgresScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
maxRetries := Common.MaxRetries
|
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 _, user := range Common.Userdict["postgresql"] {
|
||||||
for _, pass := range Common.Passwords {
|
for _, pass := range Common.Passwords {
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
pass = strings.Replace(pass, "{user}", user, -1)
|
||||||
taskChan <- struct {
|
|
||||||
user string
|
|
||||||
pass string
|
|
||||||
}{user, pass}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(taskChan)
|
|
||||||
|
|
||||||
// 启动工作线程
|
// 检查是否超时
|
||||||
var wg sync.WaitGroup
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
for i := 0; i < threads; i++ {
|
return fmt.Errorf("扫描超时")
|
||||||
wg.Add(1)
|
}
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
starttime := time.Now().Unix()
|
|
||||||
|
|
||||||
for task := range taskChan {
|
// 重试循环
|
||||||
// 重试循环
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
// 执行PostgreSQL连接
|
||||||
// 检查是否超时
|
done := make(chan struct {
|
||||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
success bool
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
err error
|
||||||
return
|
})
|
||||||
}
|
|
||||||
|
|
||||||
// 执行PostgreSQL连接
|
go func(user, pass string) {
|
||||||
done := make(chan struct {
|
success, err := PostgresConn(info, user, pass)
|
||||||
|
done <- struct {
|
||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
})
|
}{success, err}
|
||||||
|
}(user, pass)
|
||||||
|
|
||||||
go func(user, pass string) {
|
// 等待结果或超时
|
||||||
success, err := PostgresConn(info, user, pass)
|
var err error
|
||||||
done <- struct {
|
select {
|
||||||
success bool
|
case result := <-done:
|
||||||
err error
|
err = result.err
|
||||||
}{success, err}
|
if result.success && err == nil {
|
||||||
}(task.user, task.pass)
|
return nil
|
||||||
|
|
||||||
// 等待结果或超时
|
|
||||||
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("连接超时")
|
|
||||||
}
|
}
|
||||||
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
// 处理错误情况
|
err = fmt.Errorf("连接超时")
|
||||||
if err != nil {
|
|
||||||
errlog := fmt.Sprintf("PostgreSQL %v:%v %v %v %v",
|
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
|
||||||
Common.LogError(errlog)
|
|
||||||
|
|
||||||
// 检查是否需要重试
|
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
|
||||||
if retryCount == maxRetries-1 {
|
|
||||||
resultChan <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
continue // 继续重试
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break // 如果不需要重试,跳出重试循环
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
resultChan <- nil
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 等待所有线程完成
|
// 处理错误情况
|
||||||
go func() {
|
if err != nil {
|
||||||
wg.Wait()
|
errlog := fmt.Sprintf("PostgreSQL %v:%v %v %v %v",
|
||||||
close(resultChan)
|
info.Host, info.Ports, user, pass, err)
|
||||||
}()
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查结果
|
// 检查是否需要重试
|
||||||
for err := range resultChan {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if err != nil {
|
if retryCount == maxRetries-1 {
|
||||||
tmperr = err
|
return err
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
}
|
||||||
return err
|
continue // 继续重试
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break // 如果不需要重试,跳出重试循环
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
136
Plugins/RDP.go
136
Plugins/RDP.go
@ -37,130 +37,40 @@ func RdpScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
return
|
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)
|
port, _ := strconv.Atoi(info.Ports)
|
||||||
|
total := len(Common.Userdict["rdp"]) * len(Common.Passwords)
|
||||||
|
num := 0
|
||||||
|
|
||||||
// 启动工作协程
|
// 遍历用户名密码组合
|
||||||
for i := 0; i < Common.BruteThreads; i++ {
|
for _, user := range Common.Userdict["rdp"] {
|
||||||
wg.Add(1)
|
for _, pass := range Common.Passwords {
|
||||||
go func() {
|
num++
|
||||||
defer wg.Done()
|
pass = strings.Replace(pass, "{user}", user, -1)
|
||||||
for one := range brlist {
|
|
||||||
select {
|
// 尝试连接
|
||||||
case <-resultChan: // 检查是否已经找到有效凭据
|
flag, err := RdpConn(info.Host, Common.Domain, user, pass, port, Common.Timeout)
|
||||||
return
|
|
||||||
default:
|
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)
|
||||||
mutex.Lock()
|
return nil
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 分发扫描任务
|
// 连接失败
|
||||||
go func() {
|
errlog := fmt.Sprintf("(%v/%v) RDP %v:%v %v %v %v", num, total, info.Host, port, user, pass, err)
|
||||||
for _, user := range Common.Userdict["rdp"] {
|
Common.LogError(errlog)
|
||||||
for _, pass := range Common.Passwords {
|
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
|
||||||
select {
|
|
||||||
case <-resultChan: // 如果已经找到有效凭据,停止分发任务
|
|
||||||
return
|
|
||||||
case brlist <- Brutelist{user, pass}:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
close(brlist)
|
|
||||||
}()
|
|
||||||
|
|
||||||
// 等待任务完成或找到有效凭据
|
|
||||||
go func() {
|
|
||||||
wg.Wait()
|
|
||||||
close(resultChan)
|
|
||||||
}()
|
|
||||||
|
|
||||||
// 等待结果
|
|
||||||
if <-resultChan {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return tmperr
|
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连接
|
// RdpConn 尝试RDP连接
|
||||||
func RdpConn(ip, domain, user, password string, port int, timeout int64) (bool, error) {
|
func RdpConn(ip, domain, user, password string, port int, timeout int64) (bool, error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -17,116 +16,114 @@ func RabbitMQScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
maxRetries := Common.MaxRetries
|
maxRetries := Common.MaxRetries
|
||||||
threads := Common.BruteThreads
|
starttime := time.Now().Unix()
|
||||||
|
|
||||||
// 创建任务通道
|
// 先测试默认账号 guest/guest
|
||||||
taskChan := make(chan struct {
|
user, pass := "guest", "guest"
|
||||||
user string
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
pass string
|
// 检查是否超时
|
||||||
}, len(Common.Userdict["rabbitmq"])*len(Common.Passwords)+1) // +1 是为了加入guest账号
|
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
|
go func() {
|
||||||
taskChan <- struct {
|
success, err := RabbitMQConn(info, user, pass)
|
||||||
user string
|
done <- struct {
|
||||||
pass string
|
success bool
|
||||||
}{"guest", "guest"}
|
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 _, user := range Common.Userdict["rabbitmq"] {
|
||||||
for _, pass := range Common.Passwords {
|
for _, pass := range Common.Passwords {
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
pass = strings.Replace(pass, "{user}", user, -1)
|
||||||
taskChan <- struct {
|
|
||||||
user string
|
|
||||||
pass string
|
|
||||||
}{user, pass}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(taskChan)
|
|
||||||
|
|
||||||
// 启动工作线程
|
// 检查是否超时
|
||||||
var wg sync.WaitGroup
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
for i := 0; i < threads; i++ {
|
return fmt.Errorf("扫描超时")
|
||||||
wg.Add(1)
|
}
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
starttime := time.Now().Unix()
|
|
||||||
|
|
||||||
for task := range taskChan {
|
// 重试循环
|
||||||
// 重试循环
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
// 执行RabbitMQ连接
|
||||||
// 检查是否超时
|
done := make(chan struct {
|
||||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
success bool
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
err error
|
||||||
return
|
})
|
||||||
}
|
|
||||||
|
|
||||||
// 执行RabbitMQ连接
|
go func(user, pass string) {
|
||||||
done := make(chan struct {
|
success, err := RabbitMQConn(info, user, pass)
|
||||||
|
done <- struct {
|
||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
})
|
}{success, err}
|
||||||
|
}(user, pass)
|
||||||
|
|
||||||
go func(user, pass string) {
|
// 等待结果或超时
|
||||||
success, err := RabbitMQConn(info, user, pass)
|
var err error
|
||||||
done <- struct {
|
select {
|
||||||
success bool
|
case result := <-done:
|
||||||
err error
|
err = result.err
|
||||||
}{success, err}
|
if result.success && err == nil {
|
||||||
}(task.user, task.pass)
|
result := fmt.Sprintf("RabbitMQ服务 %v:%v 连接成功 用户名: %v 密码: %v",
|
||||||
|
info.Host, info.Ports, user, pass)
|
||||||
// 等待结果或超时
|
Common.LogSuccess(result)
|
||||||
var err error
|
return nil
|
||||||
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("连接超时")
|
|
||||||
}
|
}
|
||||||
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
// 处理错误情况
|
err = fmt.Errorf("连接超时")
|
||||||
if err != nil {
|
|
||||||
errlog := fmt.Sprintf("RabbitMQ服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
|
||||||
Common.LogError(errlog)
|
|
||||||
|
|
||||||
// 检查是否需要重试
|
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
|
||||||
if retryCount == maxRetries-1 {
|
|
||||||
resultChan <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
continue // 继续重试
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break // 如果不需要重试,跳出重试循环
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
resultChan <- nil
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 等待所有线程完成
|
if err != nil {
|
||||||
go func() {
|
errlog := fmt.Sprintf("RabbitMQ服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
||||||
wg.Wait()
|
info.Host, info.Ports, user, pass, err)
|
||||||
close(resultChan)
|
Common.LogError(errlog)
|
||||||
}()
|
|
||||||
|
|
||||||
// 检查结果
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
for err := range resultChan {
|
if retryCount == maxRetries-1 {
|
||||||
if err != nil {
|
return err
|
||||||
tmperr = err
|
}
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
continue
|
||||||
return err
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -489,10 +489,10 @@ func readreply(conn net.Conn) (string, error) {
|
|||||||
|
|
||||||
// testwrite 测试Redis写入权限
|
// testwrite 测试Redis写入权限
|
||||||
func testwrite(conn net.Conn) (flag bool, flagCron bool, err error) {
|
func testwrite(conn net.Conn) (flag bool, flagCron bool, err error) {
|
||||||
fmt.Println("[*] 开始测试Redis写入权限...")
|
fmt.Println("开始测试Redis写入权限...")
|
||||||
|
|
||||||
// 测试SSH目录写入权限
|
// 测试SSH目录写入权限
|
||||||
fmt.Println("[*] 正在测试 /root/.ssh/ 目录写入权限...")
|
fmt.Println("正在测试 /root/.ssh/ 目录写入权限...")
|
||||||
_, err = conn.Write([]byte("CONFIG SET dir /root/.ssh/\r\n"))
|
_, err = conn.Write([]byte("CONFIG SET dir /root/.ssh/\r\n"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("发送SSH目录测试命令失败: %v\n", err)
|
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)
|
fmt.Printf("读取SSH目录测试响应失败: %v\n", err)
|
||||||
return flag, flagCron, err
|
return flag, flagCron, err
|
||||||
}
|
}
|
||||||
fmt.Printf("[*] SSH目录测试响应: %s\n", text)
|
fmt.Printf("SSH目录测试响应: %s\n", text)
|
||||||
if strings.Contains(text, "OK") {
|
if strings.Contains(text, "OK") {
|
||||||
flag = true
|
flag = true
|
||||||
fmt.Println("SSH目录写入权限测试成功")
|
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"))
|
_, err = conn.Write([]byte("CONFIG SET dir /var/spool/cron/\r\n"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("发送定时任务目录测试命令失败: %v\n", err)
|
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)
|
fmt.Printf("读取定时任务目录测试响应失败: %v\n", err)
|
||||||
return flag, flagCron, err
|
return flag, flagCron, err
|
||||||
}
|
}
|
||||||
fmt.Printf("[*] 定时任务目录测试响应: %s\n", text)
|
fmt.Printf("定时任务目录测试响应: %s\n", text)
|
||||||
if strings.Contains(text, "OK") {
|
if strings.Contains(text, "OK") {
|
||||||
flagCron = true
|
flagCron = true
|
||||||
fmt.Println("定时任务目录写入权限测试成功")
|
fmt.Println("定时任务目录写入权限测试成功")
|
||||||
@ -531,7 +531,7 @@ func testwrite(conn net.Conn) (flag bool, flagCron bool, err error) {
|
|||||||
fmt.Println("定时任务目录写入权限测试失败")
|
fmt.Println("定时任务目录写入权限测试失败")
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("[*] 写入权限测试完成 - SSH权限: %v, Cron权限: %v\n", flag, flagCron)
|
fmt.Printf("写入权限测试完成 - SSH权限: %v, Cron权限: %v\n", flag, flagCron)
|
||||||
return flag, flagCron, err
|
return flag, flagCron, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
129
Plugins/Rsync.go
129
Plugins/Rsync.go
@ -5,7 +5,6 @@ import (
|
|||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -16,7 +15,6 @@ func RsyncScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
maxRetries := Common.MaxRetries
|
maxRetries := Common.MaxRetries
|
||||||
threads := Common.BruteThreads
|
|
||||||
|
|
||||||
// 首先测试匿名访问
|
// 首先测试匿名访问
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
@ -36,105 +34,62 @@ func RsyncScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建任务通道
|
starttime := time.Now().Unix()
|
||||||
taskChan := make(chan struct {
|
|
||||||
user string
|
|
||||||
pass string
|
|
||||||
}, len(Common.Userdict["rsync"])*len(Common.Passwords))
|
|
||||||
|
|
||||||
resultChan := make(chan error, threads)
|
// 遍历所有用户名密码组合
|
||||||
|
|
||||||
// 生成所有用户名密码组合任务
|
|
||||||
for _, user := range Common.Userdict["rsync"] {
|
for _, user := range Common.Userdict["rsync"] {
|
||||||
for _, pass := range Common.Passwords {
|
for _, pass := range Common.Passwords {
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
pass = strings.Replace(pass, "{user}", user, -1)
|
||||||
taskChan <- struct {
|
|
||||||
user string
|
|
||||||
pass string
|
|
||||||
}{user, pass}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(taskChan)
|
|
||||||
|
|
||||||
// 启动工作线程
|
// 检查是否超时
|
||||||
var wg sync.WaitGroup
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
for i := 0; i < threads; i++ {
|
return fmt.Errorf("扫描超时")
|
||||||
wg.Add(1)
|
}
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
starttime := time.Now().Unix()
|
|
||||||
|
|
||||||
for task := range taskChan {
|
// 重试循环
|
||||||
// 重试循环
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
// 执行Rsync连接
|
||||||
// 检查是否超时
|
done := make(chan struct {
|
||||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
success bool
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
err error
|
||||||
return
|
})
|
||||||
}
|
|
||||||
|
|
||||||
// 执行Rsync连接
|
go func(user, pass string) {
|
||||||
done := make(chan struct {
|
flag, err := RsyncConn(info, user, pass)
|
||||||
|
done <- struct {
|
||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
})
|
}{flag && err == nil, err}
|
||||||
|
}(user, pass)
|
||||||
|
|
||||||
go func(user, pass string) {
|
// 等待结果或超时
|
||||||
flag, err := RsyncConn(info, user, pass)
|
var err error
|
||||||
done <- struct {
|
select {
|
||||||
success bool
|
case result := <-done:
|
||||||
err error
|
err = result.err
|
||||||
}{flag && err == nil, err}
|
if result.success {
|
||||||
}(task.user, task.pass)
|
return nil
|
||||||
|
|
||||||
// 等待结果或超时
|
|
||||||
var err error
|
|
||||||
select {
|
|
||||||
case result := <-done:
|
|
||||||
err = result.err
|
|
||||||
if result.success {
|
|
||||||
resultChan <- nil
|
|
||||||
return
|
|
||||||
}
|
|
||||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
|
||||||
err = fmt.Errorf("连接超时")
|
|
||||||
}
|
}
|
||||||
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
// 处理错误情况
|
err = fmt.Errorf("连接超时")
|
||||||
if err != nil {
|
|
||||||
errlog := fmt.Sprintf("Rsync服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
|
||||||
Common.LogError(errlog)
|
|
||||||
|
|
||||||
// 检查是否需要重试
|
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
|
||||||
if retryCount == maxRetries-1 {
|
|
||||||
resultChan <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
continue // 继续重试
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break // 如果不需要重试,跳出重试循环
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
resultChan <- nil
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 等待所有线程完成
|
// 处理错误情况
|
||||||
go func() {
|
if err != nil {
|
||||||
wg.Wait()
|
errlog := fmt.Sprintf("Rsync服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
||||||
close(resultChan)
|
info.Host, info.Ports, user, pass, err)
|
||||||
}()
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查结果
|
// 检查是否需要重试
|
||||||
for err := range resultChan {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if err != nil {
|
if retryCount == maxRetries-1 {
|
||||||
tmperr = err
|
return err
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
}
|
||||||
return err
|
continue // 继续重试
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break // 如果不需要重试,跳出重试循环
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
"github.com/stacktitan/smb/smb"
|
"github.com/stacktitan/smb/smb"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -14,83 +13,39 @@ func SmbScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
threads := Common.BruteThreads
|
// 遍历所有用户
|
||||||
var wg sync.WaitGroup
|
|
||||||
successChan := make(chan struct{}, 1)
|
|
||||||
|
|
||||||
// 按用户分组处理
|
|
||||||
for _, user := range Common.Userdict["smb"] {
|
for _, user := range Common.Userdict["smb"] {
|
||||||
taskChan := make(chan string, len(Common.Passwords))
|
// 遍历该用户的所有密码
|
||||||
|
|
||||||
for _, pass := range Common.Passwords {
|
for _, pass := range Common.Passwords {
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
pass = strings.Replace(pass, "{user}", user, -1)
|
||||||
taskChan <- pass
|
|
||||||
}
|
|
||||||
close(taskChan)
|
|
||||||
|
|
||||||
for i := 0; i < threads; i++ {
|
success, err := doWithTimeOut(info, user, pass)
|
||||||
wg.Add(1)
|
if success {
|
||||||
go func(username string) {
|
if Common.Domain != "" {
|
||||||
defer wg.Done()
|
Common.LogSuccess(fmt.Sprintf("SMB认证成功 %s:%s %s\\%s:%s",
|
||||||
for pass := range taskChan {
|
info.Host, info.Ports, Common.Domain, user, pass))
|
||||||
select {
|
} else {
|
||||||
case <-successChan:
|
Common.LogSuccess(fmt.Sprintf("SMB认证成功 %s:%s %s:%s",
|
||||||
return
|
info.Host, info.Ports, user, pass))
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}(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(100 * time.Millisecond)
|
||||||
// 等待日志打印完成
|
|
||||||
time.Sleep(500 * time.Millisecond)
|
if strings.Contains(err.Error(), "账号锁定") {
|
||||||
Common.LogWG.Wait()
|
// 账号锁定时跳过当前用户的剩余密码
|
||||||
return nil
|
break // 跳出密码循环,继续下一个用户
|
||||||
default:
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 主函数结束前多等待一会
|
|
||||||
time.Sleep(500 * time.Millisecond)
|
|
||||||
Common.LogWG.Wait()
|
|
||||||
// 最后再等待一下,确保所有日志都打印完成
|
|
||||||
time.Sleep(500 * time.Millisecond)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
225
Plugins/SMB2.go
225
Plugins/SMB2.go
@ -6,7 +6,6 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hirochachacha/go-smb2"
|
"github.com/hirochachacha/go-smb2"
|
||||||
@ -27,110 +26,59 @@ func SmbScan2(info *Common.HostInfo) (tmperr error) {
|
|||||||
return smbPasswordScan(info)
|
return smbPasswordScan(info)
|
||||||
}
|
}
|
||||||
|
|
||||||
// smbPasswordScan 使用密码进行认证扫描
|
|
||||||
func smbPasswordScan(info *Common.HostInfo) error {
|
func smbPasswordScan(info *Common.HostInfo) error {
|
||||||
if Common.DisableBrute {
|
if Common.DisableBrute {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
threads := Common.BruteThreads
|
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
successChan := make(chan struct{}, 1)
|
|
||||||
hasprint := false
|
hasprint := false
|
||||||
var hasPrintMutex sync.Mutex
|
|
||||||
|
|
||||||
// 改成按用户分组处理
|
// 遍历每个用户
|
||||||
for _, user := range Common.Userdict["smb"] {
|
for _, user := range Common.Userdict["smb"] {
|
||||||
// 为每个用户创建密码任务通道
|
// 遍历该用户的所有密码
|
||||||
taskChan := make(chan string, len(Common.Passwords))
|
|
||||||
|
|
||||||
// 生成该用户的所有密码任务
|
|
||||||
for _, pass := range Common.Passwords {
|
for _, pass := range Common.Passwords {
|
||||||
pass = strings.ReplaceAll(pass, "{user}", user)
|
pass = strings.ReplaceAll(pass, "{user}", user)
|
||||||
taskChan <- pass
|
|
||||||
}
|
|
||||||
close(taskChan)
|
|
||||||
|
|
||||||
// 启动工作线程
|
// 重试循环
|
||||||
for i := 0; i < threads; i++ {
|
for retryCount := 0; retryCount < Common.MaxRetries; retryCount++ {
|
||||||
wg.Add(1)
|
success, err, printed := Smb2Con(info, user, pass, []byte{}, hasprint)
|
||||||
go func(username string) {
|
|
||||||
defer wg.Done()
|
|
||||||
|
|
||||||
for pass := range taskChan {
|
if printed {
|
||||||
select {
|
hasprint = true
|
||||||
case <-successChan:
|
}
|
||||||
return
|
|
||||||
default:
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重试循环
|
if success {
|
||||||
for retryCount := 0; retryCount < Common.MaxRetries; retryCount++ {
|
logSuccessfulAuth(info, user, pass, []byte{})
|
||||||
hasPrintMutex.Lock()
|
return nil
|
||||||
currentHasPrint := hasprint
|
}
|
||||||
hasPrintMutex.Unlock()
|
|
||||||
|
|
||||||
success, err, printed := Smb2Con(info, username, pass, []byte{}, currentHasPrint)
|
if err != nil {
|
||||||
|
logFailedAuth(info, user, pass, []byte{}, err)
|
||||||
|
|
||||||
if printed {
|
// 检查是否账户锁定
|
||||||
hasPrintMutex.Lock()
|
if strings.Contains(err.Error(), "user account has been automatically locked") {
|
||||||
hasprint = true
|
// 账户锁定,跳过该用户的剩余密码
|
||||||
hasPrintMutex.Unlock()
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
}
|
|
||||||
|
|
||||||
if success {
|
|
||||||
logSuccessfulAuth(info, username, pass, []byte{})
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
successChan <- struct{}{}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logFailedAuth(info, username, pass, []byte{}, err)
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
|
|
||||||
// 检查是否账户锁定
|
|
||||||
if strings.Contains(err.Error(), "user account has been automatically locked") {
|
|
||||||
// 发现账户锁定,清空任务通道并返回
|
|
||||||
for range taskChan {
|
|
||||||
// 清空通道
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 其他登录失败情况
|
|
||||||
if strings.Contains(err.Error(), "LOGIN_FAILED") ||
|
|
||||||
strings.Contains(err.Error(), "Authentication failed") ||
|
|
||||||
strings.Contains(err.Error(), "attempted logon is invalid") ||
|
|
||||||
strings.Contains(err.Error(), "bad username or authentication") {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if retryCount < Common.MaxRetries-1 {
|
|
||||||
time.Sleep(time.Second * time.Duration(retryCount+2))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
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)
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Wait() // 等待当前用户的所有密码尝试完成
|
|
||||||
|
|
||||||
// 检查是否已经找到正确密码
|
|
||||||
select {
|
|
||||||
case <-successChan:
|
|
||||||
return nil
|
|
||||||
default:
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
time.Sleep(200 * time.Millisecond)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,94 +87,49 @@ func smbHashScan(info *Common.HostInfo) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
threads := Common.BruteThreads
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
successChan := make(chan struct{}, 1)
|
|
||||||
hasprint := false
|
hasprint := false
|
||||||
var hasPrintMutex sync.Mutex
|
|
||||||
|
|
||||||
// 按用户分组处理
|
// 遍历每个用户
|
||||||
for _, user := range Common.Userdict["smb"] {
|
for _, user := range Common.Userdict["smb"] {
|
||||||
// 为每个用户创建hash任务通道
|
// 遍历该用户的所有hash
|
||||||
taskChan := make(chan []byte, len(Common.HashBytes))
|
|
||||||
|
|
||||||
// 生成该用户的所有hash任务
|
|
||||||
for _, hash := range Common.HashBytes {
|
for _, hash := range Common.HashBytes {
|
||||||
taskChan <- hash
|
// 重试循环
|
||||||
}
|
for retryCount := 0; retryCount < Common.MaxRetries; retryCount++ {
|
||||||
close(taskChan)
|
success, err, printed := Smb2Con(info, user, "", hash, hasprint)
|
||||||
|
|
||||||
// 启动工作线程
|
if printed {
|
||||||
for i := 0; i < threads; i++ {
|
hasprint = true
|
||||||
wg.Add(1)
|
}
|
||||||
go func(username string) {
|
|
||||||
defer wg.Done()
|
|
||||||
|
|
||||||
for hash := range taskChan {
|
if success {
|
||||||
select {
|
logSuccessfulAuth(info, user, "", hash)
|
||||||
case <-successChan:
|
return nil
|
||||||
return
|
}
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重试循环
|
if err != nil {
|
||||||
for retryCount := 0; retryCount < Common.MaxRetries; retryCount++ {
|
logFailedAuth(info, user, "", hash, err)
|
||||||
hasPrintMutex.Lock()
|
|
||||||
currentHasPrint := hasprint
|
|
||||||
hasPrintMutex.Unlock()
|
|
||||||
|
|
||||||
success, err, printed := Smb2Con(info, username, "", hash, currentHasPrint)
|
// 检查是否账户锁定
|
||||||
|
if strings.Contains(err.Error(), "user account has been automatically locked") {
|
||||||
if printed {
|
// 账户锁定,跳过该用户的剩余hash
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
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)
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Wait() // 等待当前用户的所有hash尝试完成
|
|
||||||
|
|
||||||
// 检查是否已经找到正确凭据
|
|
||||||
select {
|
|
||||||
case <-successChan:
|
|
||||||
return nil
|
|
||||||
default:
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
129
Plugins/SMTP.go
129
Plugins/SMTP.go
@ -6,7 +6,6 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/smtp"
|
"net/smtp"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -17,7 +16,6 @@ func SmtpScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
maxRetries := Common.MaxRetries
|
maxRetries := Common.MaxRetries
|
||||||
threads := Common.BruteThreads
|
|
||||||
|
|
||||||
// 先测试匿名访问
|
// 先测试匿名访问
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
@ -36,105 +34,62 @@ func SmtpScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建任务通道
|
starttime := time.Now().Unix()
|
||||||
taskChan := make(chan struct {
|
|
||||||
user string
|
|
||||||
pass string
|
|
||||||
}, len(Common.Userdict["smtp"])*len(Common.Passwords))
|
|
||||||
|
|
||||||
resultChan := make(chan error, threads)
|
// 遍历所有用户名密码组合
|
||||||
|
|
||||||
// 生成所有用户名密码组合任务
|
|
||||||
for _, user := range Common.Userdict["smtp"] {
|
for _, user := range Common.Userdict["smtp"] {
|
||||||
for _, pass := range Common.Passwords {
|
for _, pass := range Common.Passwords {
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
pass = strings.Replace(pass, "{user}", user, -1)
|
||||||
taskChan <- struct {
|
|
||||||
user string
|
|
||||||
pass string
|
|
||||||
}{user, pass}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(taskChan)
|
|
||||||
|
|
||||||
// 启动工作线程
|
// 检查是否超时
|
||||||
var wg sync.WaitGroup
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
for i := 0; i < threads; i++ {
|
return fmt.Errorf("扫描超时")
|
||||||
wg.Add(1)
|
}
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
starttime := time.Now().Unix()
|
|
||||||
|
|
||||||
for task := range taskChan {
|
// 重试循环
|
||||||
// 重试循环
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
// 执行SMTP连接
|
||||||
// 检查是否超时
|
done := make(chan struct {
|
||||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
success bool
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
err error
|
||||||
return
|
})
|
||||||
}
|
|
||||||
|
|
||||||
// 执行SMTP连接
|
go func(user, pass string) {
|
||||||
done := make(chan struct {
|
flag, err := SmtpConn(info, user, pass)
|
||||||
|
done <- struct {
|
||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
})
|
}{flag, err}
|
||||||
|
}(user, pass)
|
||||||
|
|
||||||
go func(user, pass string) {
|
// 等待结果或超时
|
||||||
flag, err := SmtpConn(info, user, pass)
|
var err error
|
||||||
done <- struct {
|
select {
|
||||||
success bool
|
case result := <-done:
|
||||||
err error
|
err = result.err
|
||||||
}{flag, err}
|
if result.success && err == nil {
|
||||||
}(task.user, task.pass)
|
return nil
|
||||||
|
|
||||||
// 等待结果或超时
|
|
||||||
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("连接超时")
|
|
||||||
}
|
}
|
||||||
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
// 处理错误情况
|
err = fmt.Errorf("连接超时")
|
||||||
if err != nil {
|
|
||||||
errlog := fmt.Sprintf("SMTP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
|
||||||
Common.LogError(errlog)
|
|
||||||
|
|
||||||
// 检查是否需要重试
|
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
|
||||||
if retryCount == maxRetries-1 {
|
|
||||||
resultChan <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
continue // 继续重试
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break // 如果不需要重试,跳出重试循环
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
resultChan <- nil
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 等待所有线程完成
|
// 处理错误情况
|
||||||
go func() {
|
if err != nil {
|
||||||
wg.Wait()
|
errlog := fmt.Sprintf("SMTP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
||||||
close(resultChan)
|
info.Host, info.Ports, user, pass, err)
|
||||||
}()
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查结果
|
// 检查是否需要重试
|
||||||
for err := range resultChan {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if err != nil {
|
if retryCount == maxRetries-1 {
|
||||||
tmperr = err
|
return err
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
}
|
||||||
return err
|
continue // 继续重试
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break // 如果不需要重试,跳出重试循环
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
141
Plugins/SNMP.go
141
Plugins/SNMP.go
@ -6,7 +6,6 @@ import (
|
|||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -17,106 +16,66 @@ func SNMPScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
maxRetries := Common.MaxRetries
|
maxRetries := Common.MaxRetries
|
||||||
threads := Common.BruteThreads
|
|
||||||
|
|
||||||
portNum, _ := strconv.Atoi(info.Ports)
|
portNum, _ := strconv.Atoi(info.Ports)
|
||||||
defaultCommunities := []string{"public", "private", "cisco", "community"}
|
defaultCommunities := []string{"public", "private", "cisco", "community"}
|
||||||
|
starttime := time.Now().Unix()
|
||||||
|
timeout := time.Duration(Common.Timeout) * time.Second
|
||||||
|
|
||||||
// 创建任务通道
|
// 遍历所有 community
|
||||||
taskChan := make(chan string, len(defaultCommunities))
|
|
||||||
resultChan := make(chan error, threads)
|
|
||||||
|
|
||||||
// 生成所有community任务
|
|
||||||
for _, community := range defaultCommunities {
|
for _, community := range defaultCommunities {
|
||||||
taskChan <- community
|
// 检查是否超时
|
||||||
}
|
if time.Now().Unix()-starttime > int64(timeout.Seconds()) {
|
||||||
close(taskChan)
|
return fmt.Errorf("扫描超时")
|
||||||
|
}
|
||||||
|
|
||||||
// 启动工作线程
|
// 重试循环
|
||||||
var wg sync.WaitGroup
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
for i := 0; i < threads; i++ {
|
// 执行SNMP连接
|
||||||
wg.Add(1)
|
done := make(chan struct {
|
||||||
go func() {
|
success bool
|
||||||
defer wg.Done()
|
err error
|
||||||
starttime := time.Now().Unix()
|
})
|
||||||
|
|
||||||
for community := range taskChan {
|
go func(community string) {
|
||||||
// 重试循环
|
success, err := SNMPConnect(info, community, portNum)
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
done <- struct {
|
||||||
// 检查是否超时
|
success bool
|
||||||
timeout := time.Duration(Common.Timeout) * time.Second
|
err error
|
||||||
if time.Now().Unix()-starttime > int64(timeout.Seconds()) {
|
}{success, err}
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
}(community)
|
||||||
return
|
|
||||||
|
// 等待结果或超时
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
continue // 继续重试
|
||||||
// 执行SNMP连接
|
|
||||||
done := make(chan struct {
|
|
||||||
success bool
|
|
||||||
err error
|
|
||||||
})
|
|
||||||
|
|
||||||
go func(community string) {
|
|
||||||
success, err := SNMPConnect(info, community, portNum)
|
|
||||||
done <- struct {
|
|
||||||
success bool
|
|
||||||
err error
|
|
||||||
}{success, err}
|
|
||||||
}(community)
|
|
||||||
|
|
||||||
// 等待结果或超时
|
|
||||||
var err error
|
|
||||||
select {
|
|
||||||
case result := <-done:
|
|
||||||
err = result.err
|
|
||||||
if result.success && err == nil {
|
|
||||||
// 连接成功
|
|
||||||
successLog := fmt.Sprintf("SNMP服务 %v:%v community: %v 连接成功",
|
|
||||||
info.Host, info.Ports, community)
|
|
||||||
Common.LogSuccess(successLog)
|
|
||||||
resultChan <- nil
|
|
||||||
return
|
|
||||||
}
|
|
||||||
case <-time.After(timeout):
|
|
||||||
err = fmt.Errorf("连接超时")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理错误情况
|
|
||||||
if err != nil {
|
|
||||||
errlog := fmt.Sprintf("SNMP服务 %v:%v 尝试失败 community: %v 错误: %v",
|
|
||||||
info.Host, info.Ports, community, err)
|
|
||||||
Common.LogError(errlog)
|
|
||||||
|
|
||||||
// 检查是否需要重试
|
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
|
||||||
if retryCount == maxRetries-1 {
|
|
||||||
resultChan <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
continue // 继续重试
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break // 如果不需要重试,跳出重试循环
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resultChan <- nil
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 等待所有线程完成
|
break // 如果不需要重试,跳出重试循环
|
||||||
go func() {
|
|
||||||
wg.Wait()
|
|
||||||
close(resultChan)
|
|
||||||
}()
|
|
||||||
|
|
||||||
// 检查结果
|
|
||||||
for err := range resultChan {
|
|
||||||
if err != nil {
|
|
||||||
tmperr = err
|
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
150
Plugins/SSH.go
150
Plugins/SSH.go
@ -1,13 +1,13 @@
|
|||||||
package Plugins
|
package Plugins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -17,97 +17,67 @@ func SshScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
maxRetries := Common.MaxRetries
|
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 _, user := range Common.Userdict["ssh"] {
|
||||||
for _, pass := range Common.Passwords {
|
for _, pass := range Common.Passwords {
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
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++ {
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
wg.Add(1)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(Common.Timeout)*time.Second)
|
||||||
go func() {
|
done := make(chan struct {
|
||||||
defer wg.Done()
|
success bool
|
||||||
for task := range taskChan {
|
err error
|
||||||
// 重试循环
|
}, 1)
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
|
||||||
done := make(chan struct {
|
go func(user, pass string) {
|
||||||
|
success, err := SshConn(info, user, pass)
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
case done <- struct {
|
||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
})
|
}{success, err}:
|
||||||
|
|
||||||
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("连接超时")
|
|
||||||
}
|
}
|
||||||
|
}(user, pass)
|
||||||
|
|
||||||
if err != nil {
|
var err error
|
||||||
errlog := fmt.Sprintf("SSH认证失败 %v:%v User:%v Pass:%v Err:%v",
|
select {
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
case result := <-done:
|
||||||
Common.LogError(errlog)
|
err = result.err
|
||||||
|
if result.success {
|
||||||
// 检查是否是已知错误,如果是则等待3秒后重试
|
successLog := fmt.Sprintf("SSH认证成功 %v:%v User:%v Pass:%v",
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
info.Host, info.Ports, user, pass)
|
||||||
if retryCount == maxRetries-1 {
|
Common.LogSuccess(successLog)
|
||||||
resultChan <- err
|
time.Sleep(100 * time.Millisecond)
|
||||||
return
|
cancel()
|
||||||
}
|
return nil
|
||||||
continue // 继续重试
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
case <-ctx.Done():
|
||||||
if Common.SshKeyPath != "" {
|
err = fmt.Errorf("连接超时")
|
||||||
resultChan <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
break // 如果不需要重试,跳出重试循环
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
resultChan <- nil
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
cancel()
|
||||||
wg.Wait()
|
|
||||||
close(resultChan)
|
|
||||||
}()
|
|
||||||
|
|
||||||
// 检查结果
|
if err != nil {
|
||||||
for err := range resultChan {
|
errlog := fmt.Sprintf("SSH认证失败 %v:%v User:%v Pass:%v Err:%v",
|
||||||
if err != nil {
|
info.Host, info.Ports, user, pass, err)
|
||||||
tmperr = err
|
Common.LogError(errlog)
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
|
||||||
return err
|
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()
|
defer session.Close()
|
||||||
|
|
||||||
flag = true
|
// 如果需要执行命令
|
||||||
|
|
||||||
if Common.Command != "" {
|
if Common.Command != "" {
|
||||||
output, err := session.CombinedOutput(Common.Command)
|
_, err := session.CombinedOutput(Common.Command)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return true, err
|
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
|
||||||
}
|
}
|
||||||
|
@ -153,7 +153,7 @@ func SmbGhostScan(info *Common.HostInfo) error {
|
|||||||
bytes.Equal(buff[74:76], []byte{0x02, 0x00}) {
|
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)
|
Common.LogSuccess(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -19,120 +18,74 @@ func TelnetScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
maxRetries := Common.MaxRetries
|
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 _, user := range Common.Userdict["telnet"] {
|
||||||
for _, pass := range Common.Passwords {
|
for _, pass := range Common.Passwords {
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
pass = strings.Replace(pass, "{user}", user, -1)
|
||||||
taskChan <- struct {
|
|
||||||
user string
|
|
||||||
pass string
|
|
||||||
}{user, pass}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(taskChan)
|
|
||||||
|
|
||||||
// 启动工作线程
|
// 检查是否超时
|
||||||
var wg sync.WaitGroup
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
for i := 0; i < threads; i++ {
|
return fmt.Errorf("扫描超时")
|
||||||
wg.Add(1)
|
}
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
starttime := time.Now().Unix()
|
|
||||||
|
|
||||||
for task := range taskChan {
|
// 重试循环
|
||||||
// 重试循环
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
// 执行Telnet连接
|
||||||
// 检查是否超时
|
done := make(chan struct {
|
||||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
success bool
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
noAuth bool
|
||||||
return
|
err error
|
||||||
}
|
})
|
||||||
|
|
||||||
// 执行Telnet连接
|
go func(user, pass string) {
|
||||||
done := make(chan struct {
|
flag, err := telnetConn(info, user, pass)
|
||||||
|
done <- struct {
|
||||||
success bool
|
success bool
|
||||||
noAuth bool
|
noAuth bool
|
||||||
err error
|
err error
|
||||||
})
|
}{err == nil, flag, err}
|
||||||
|
}(user, pass)
|
||||||
|
|
||||||
go func(user, pass string) {
|
// 等待结果或超时
|
||||||
flag, err := telnetConn(info, user, pass)
|
var err error
|
||||||
done <- struct {
|
select {
|
||||||
success bool
|
case result := <-done:
|
||||||
noAuth bool
|
err = result.err
|
||||||
err error
|
if result.noAuth {
|
||||||
}{err == nil, flag, err}
|
// 无需认证
|
||||||
}(task.user, task.pass)
|
result := fmt.Sprintf("Telnet服务 %v:%v 无需认证",
|
||||||
|
info.Host, info.Ports)
|
||||||
// 等待结果或超时
|
Common.LogSuccess(result)
|
||||||
var err error
|
return nil
|
||||||
select {
|
} else if result.success {
|
||||||
case result := <-done:
|
// 成功爆破
|
||||||
err = result.err
|
result := fmt.Sprintf("Telnet服务 %v:%v 用户名:%v 密码:%v",
|
||||||
if result.noAuth {
|
info.Host, info.Ports, user, pass)
|
||||||
// 无需认证
|
Common.LogSuccess(result)
|
||||||
result := fmt.Sprintf("Telnet服务 %v:%v 无需认证",
|
return nil
|
||||||
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("连接超时")
|
|
||||||
}
|
}
|
||||||
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
// 处理错误情况
|
err = fmt.Errorf("连接超时")
|
||||||
if err != nil {
|
|
||||||
errlog := fmt.Sprintf("Telnet连接失败 %v:%v 用户名:%v 密码:%v 错误:%v",
|
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
|
||||||
Common.LogError(errlog)
|
|
||||||
|
|
||||||
// 检查是否需要重试
|
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
|
||||||
if retryCount == maxRetries-1 {
|
|
||||||
resultChan <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
continue // 继续重试
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break // 如果不需要重试,跳出重试循环
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
resultChan <- nil
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 等待所有线程完成
|
// 处理错误情况
|
||||||
go func() {
|
if err != nil {
|
||||||
wg.Wait()
|
errlog := fmt.Sprintf("Telnet连接失败 %v:%v 用户名:%v 密码:%v 错误:%v",
|
||||||
close(resultChan)
|
info.Host, info.Ports, user, pass, err)
|
||||||
}()
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查结果
|
// 检查是否需要重试
|
||||||
for err := range resultChan {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if err != nil {
|
if retryCount == maxRetries-1 {
|
||||||
tmperr = err
|
return err
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
}
|
||||||
return err
|
continue // 继续重试
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break // 如果不需要重试,跳出重试循环
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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("认证失败")
|
|
||||||
}
|
|
138
Plugins/VNC.go
138
Plugins/VNC.go
@ -5,7 +5,6 @@ import (
|
|||||||
"github.com/mitchellh/go-vnc"
|
"github.com/mitchellh/go-vnc"
|
||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -16,103 +15,64 @@ func VncScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
maxRetries := Common.MaxRetries
|
maxRetries := Common.MaxRetries
|
||||||
threads := Common.BruteThreads
|
|
||||||
modename := "vnc"
|
modename := "vnc"
|
||||||
|
starttime := time.Now().Unix()
|
||||||
|
|
||||||
// 创建任务通道
|
// 遍历所有密码
|
||||||
taskChan := make(chan string, len(Common.Passwords))
|
|
||||||
resultChan := make(chan error, threads)
|
|
||||||
|
|
||||||
// 生成所有密码任务
|
|
||||||
for _, pass := range Common.Passwords {
|
for _, pass := range Common.Passwords {
|
||||||
taskChan <- pass
|
// 检查是否超时
|
||||||
}
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
close(taskChan)
|
return fmt.Errorf("扫描超时")
|
||||||
|
}
|
||||||
|
|
||||||
// 启动工作线程
|
// 重试循环
|
||||||
var wg sync.WaitGroup
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
for i := 0; i < threads; i++ {
|
// 执行VNC连接
|
||||||
wg.Add(1)
|
done := make(chan struct {
|
||||||
go func() {
|
success bool
|
||||||
defer wg.Done()
|
err error
|
||||||
starttime := time.Now().Unix()
|
})
|
||||||
|
|
||||||
for pass := range taskChan {
|
go func(pass string) {
|
||||||
// 重试循环
|
success, err := VncConn(info, pass)
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
done <- struct {
|
||||||
// 检查是否超时
|
success bool
|
||||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
err error
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
}{success, err}
|
||||||
return
|
}(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
|
||||||
}
|
}
|
||||||
|
continue // 继续重试
|
||||||
// 执行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 // 如果不需要重试,跳出重试循环
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resultChan <- nil
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 等待所有线程完成
|
break // 如果不需要重试,跳出重试循环
|
||||||
go func() {
|
|
||||||
wg.Wait()
|
|
||||||
close(resultChan)
|
|
||||||
}()
|
|
||||||
|
|
||||||
// 检查结果
|
|
||||||
for err := range resultChan {
|
|
||||||
if err != nil {
|
|
||||||
tmperr = err
|
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -34,130 +33,87 @@ func WmiExec(info *Common.HostInfo) (tmperr error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
maxRetries := Common.MaxRetries
|
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 _, user := range Common.Userdict["smb"] {
|
||||||
for _, pass := range Common.Passwords {
|
for _, pass := range Common.Passwords {
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
pass = strings.Replace(pass, "{user}", user, -1)
|
||||||
taskChan <- struct {
|
|
||||||
user string
|
// 检查是否超时
|
||||||
pass string
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
}{user, pass}
|
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值,只尝试一次密码
|
// 如果是32位hash值,只尝试一次密码
|
||||||
if len(Common.HashValue) == 32 {
|
if len(Common.HashValue) == 32 {
|
||||||
break
|
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
|
return tmperr
|
||||||
}
|
}
|
||||||
|
@ -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)
|
|
||||||
}
|
|
54
README_EN.md
54
README_EN.md
@ -227,34 +227,34 @@ https://github.com/jjf012/gopoc
|
|||||||
|
|
||||||
|
|
||||||
# 10. Dynamics
|
# 10. Dynamics
|
||||||
[+] 2022/11/19 Add hash collision, wmiexec echo free command execution function
|
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/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/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/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.
|
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/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/2/25 Add - m webonly to skip port scanning and directly access http. Thanks @ AgeloVito
|
||||||
[+] 2022/1/11 Add oracle password explosion.
|
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.
|
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/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/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/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/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/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/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/22 Modify webtitle module and add gbk decoding.
|
||||||
[+] 2021/4/21 Add netbios detection and domain control identification functions.
|
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/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/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/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.
|
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.
|
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/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/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/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 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/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/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/11/15 Support importt ip from file, -hf ip.txt, and process de duplication ips.
|
||||||
|
|
||||||
[url-doczh]: README.md
|
[url-doczh]: README.md
|
@ -58,7 +58,7 @@ func InfoCheck(Url string, CheckData *[]CheckDatas) []string {
|
|||||||
|
|
||||||
// 输出结果
|
// 输出结果
|
||||||
if len(matchedInfos) > 0 {
|
if len(matchedInfos) > 0 {
|
||||||
result := fmt.Sprintf("[+] 发现指纹 目标: %-25v 指纹: %s", Url, matchedInfos)
|
result := fmt.Sprintf("发现指纹 目标: %-25v 指纹: %s", Url, matchedInfos)
|
||||||
Common.LogSuccess(result)
|
Common.LogSuccess(result)
|
||||||
return matchedInfos
|
return matchedInfos
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ func initpoc() {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 从指定目录加载POC
|
// 从指定目录加载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 {
|
err := filepath.Walk(Common.PocPath, func(path string, info os.FileInfo, err error) error {
|
||||||
if err != nil || info == nil {
|
if err != nil || info == nil {
|
||||||
return err
|
return err
|
||||||
@ -98,7 +98,7 @@ func initpoc() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Common.LogError(fmt.Sprintf("[-] 加载外部POC失败: %v", err))
|
Common.LogError(fmt.Sprintf("加载外部POC失败: %v", err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -256,7 +256,7 @@ func LoadMultiPoc(Pocs embed.FS, pocname string) []*Poc {
|
|||||||
if p, err := LoadPoc(f, Pocs); err == nil {
|
if p, err := LoadPoc(f, Pocs); err == nil {
|
||||||
pocs = append(pocs, p)
|
pocs = append(pocs, p)
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("[-] POC加载失败 %s: %v\n", f, err)
|
fmt.Printf("POC加载失败 %s: %v\n", f, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pocs
|
return pocs
|
||||||
@ -268,14 +268,14 @@ func LoadPoc(fileName string, Pocs embed.FS) (*Poc, error) {
|
|||||||
// 读取POC文件内容
|
// 读取POC文件内容
|
||||||
yamlFile, err := Pocs.ReadFile("pocs/" + fileName)
|
yamlFile, err := Pocs.ReadFile("pocs/" + fileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("[-] POC文件读取失败 %s: %v\n", fileName, err)
|
fmt.Printf("POC文件读取失败 %s: %v\n", fileName, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解析YAML内容
|
// 解析YAML内容
|
||||||
err = yaml.Unmarshal(yamlFile, p)
|
err = yaml.Unmarshal(yamlFile, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("[-] POC解析失败 %s: %v\n", fileName, err)
|
fmt.Printf("POC解析失败 %s: %v\n", fileName, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return p, 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 {
|
func SelectPoc(Pocs embed.FS, pocname string) []string {
|
||||||
entries, err := Pocs.ReadDir("pocs")
|
entries, err := Pocs.ReadDir("pocs")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("[-] 读取POC目录失败: %v\n", err)
|
fmt.Printf("读取POC目录失败: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var foundFiles []string
|
var foundFiles []string
|
||||||
@ -304,14 +304,14 @@ func LoadPocbyPath(fileName string) (*Poc, error) {
|
|||||||
// 读取POC文件内容
|
// 读取POC文件内容
|
||||||
data, err := os.ReadFile(fileName)
|
data, err := os.ReadFile(fileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("[-] POC文件读取失败 %s: %v\n", fileName, err)
|
fmt.Printf("POC文件读取失败 %s: %v\n", fileName, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解析YAML内容
|
// 解析YAML内容
|
||||||
err = yaml.Unmarshal(data, p)
|
err = yaml.Unmarshal(data, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("[-] POC解析失败 %s: %v\n", fileName, err)
|
fmt.Printf("POC解析失败 %s: %v\n", fileName, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return p, err
|
return p, err
|
||||||
|
4
go.mod
4
go.mod
@ -68,10 +68,14 @@ require (
|
|||||||
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect
|
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // 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/pierrec/lz4/v4 v4.1.21 // indirect
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // 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/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
|
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
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
6
go.sum
6
go.sum
@ -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/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/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
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.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/go-homedir v1.1.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=
|
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/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 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
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/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.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
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/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 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
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/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 h1:d29xgHDK4aa3ljm/e/yThdJxygf26zJyRPBunrWT65k=
|
||||||
github.com/shadow1ng/grdp v1.0.3/go.mod h1:3ZMSLWUvPOwoRr6IwpAQCzKbLEZqT80sbyxxe6YgcTg=
|
github.com/shadow1ng/grdp v1.0.3/go.mod h1:3ZMSLWUvPOwoRr6IwpAQCzKbLEZqT80sbyxxe6YgcTg=
|
||||||
|
8
main.go
8
main.go
@ -1,21 +1,19 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
"github.com/shadow1ng/fscan/Core"
|
"github.com/shadow1ng/fscan/Core"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
Common.InitLogger()
|
||||||
|
defer Common.CloseLogger() // 确保程序退出时关闭日志文件
|
||||||
|
|
||||||
start := time.Now()
|
|
||||||
var Info Common.HostInfo
|
var Info Common.HostInfo
|
||||||
Common.Flag(&Info)
|
Common.Flag(&Info)
|
||||||
if err := Common.Parse(&Info); err != nil {
|
if err := Common.Parse(&Info); err != nil {
|
||||||
os.Exit(1) // 或者其他错误处理
|
os.Exit(1) // 直接退出即可,日志已经同步写入
|
||||||
}
|
}
|
||||||
Core.Scan(Info)
|
Core.Scan(Info)
|
||||||
fmt.Printf("[*] 扫描结束,耗时: %s\n", time.Since(start))
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user