mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-06-21 02:10:55 +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()
|
||||||
}
|
}
|
||||||
|
210
Common/Log.go
210
Common/Log.go
@ -19,18 +19,13 @@ 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 {
|
} else {
|
||||||
fmt.Println(logMsg)
|
fmt.Println(logMsg)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
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)
|
|
||||||
|
printLog(entry)
|
||||||
|
if fileWriter != nil {
|
||||||
|
fileWriter.write(entry)
|
||||||
|
}
|
||||||
|
|
||||||
status.mu.Lock()
|
status.mu.Lock()
|
||||||
status.lastSuccess = time.Now()
|
status.lastSuccess = time.Now()
|
||||||
status.mu.Unlock()
|
status.mu.Unlock()
|
||||||
default:
|
|
||||||
// 如果通道已关闭或已满,直接打印
|
|
||||||
printLog(&LogEntry{
|
|
||||||
Level: LogLevelSuccess,
|
|
||||||
Time: time.Now(),
|
|
||||||
Content: result,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// JsonOutput JSON输出的结构体
|
if ProgressBar != nil {
|
||||||
type JsonOutput struct {
|
ProgressBar.RenderBlank()
|
||||||
Level string `json:"level"`
|
|
||||||
Timestamp time.Time `json:"timestamp"`
|
|
||||||
Message string `json:"message"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// processLogs 处理日志信息
|
|
||||||
func processLogs() {
|
|
||||||
writer := newBufferedFileWriter()
|
|
||||||
defer writer.close()
|
|
||||||
|
|
||||||
for entry := range results {
|
|
||||||
if !Silent {
|
|
||||||
printLog(entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
if writer != nil {
|
|
||||||
writer.write(entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
logWG.Done()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newBufferedFileWriter() *bufferedFileWriter {
|
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)
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
w.writer.Flush()
|
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,43 +33,20 @@ 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
|
|
||||||
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) {
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
return fmt.Errorf("扫描超时")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 重试循环
|
||||||
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
// 执行连接测试
|
// 执行连接测试
|
||||||
done := make(chan struct {
|
done := make(chan struct {
|
||||||
success bool
|
success bool
|
||||||
@ -84,7 +59,7 @@ func ActiveMQScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
}{flag, err}
|
}{flag, err}
|
||||||
}(task.user, task.pass)
|
}(user, pass)
|
||||||
|
|
||||||
// 等待结果或超时
|
// 等待结果或超时
|
||||||
var err error
|
var err error
|
||||||
@ -92,8 +67,7 @@ func ActiveMQScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
case result := <-done:
|
case result := <-done:
|
||||||
err = result.err
|
err = result.err
|
||||||
if result.success {
|
if result.success {
|
||||||
resultChan <- nil
|
return nil
|
||||||
return
|
|
||||||
}
|
}
|
||||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
err = fmt.Errorf("连接超时")
|
err = fmt.Errorf("连接超时")
|
||||||
@ -101,13 +75,12 @@ func ActiveMQScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errlog := fmt.Sprintf("ActiveMQ服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
errlog := fmt.Sprintf("ActiveMQ服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
info.Host, info.Ports, user, pass, err)
|
||||||
Common.LogError(errlog)
|
Common.LogError(errlog)
|
||||||
|
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if retryCount == maxRetries-1 {
|
if retryCount == maxRetries-1 {
|
||||||
resultChan <- err
|
return err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -116,24 +89,6 @@ func ActiveMQScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
break
|
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
|
||||||
@ -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,41 +32,18 @@ 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
|
|
||||||
for i := 0; i < threads; i++ {
|
|
||||||
wg.Add(1)
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
for task := range taskChan {
|
|
||||||
// 重试循环
|
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
|
||||||
// 检查是否超时
|
// 检查是否超时
|
||||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
return fmt.Errorf("扫描超时")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 重试循环
|
||||||
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
// 执行连接
|
// 执行连接
|
||||||
done := make(chan struct {
|
done := make(chan struct {
|
||||||
success bool
|
success bool
|
||||||
@ -81,7 +56,7 @@ func CassandraScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
}{success, err}
|
}{success, err}
|
||||||
}(task.user, task.pass)
|
}(user, pass)
|
||||||
|
|
||||||
// 等待结果或超时
|
// 等待结果或超时
|
||||||
var err error
|
var err error
|
||||||
@ -89,8 +64,7 @@ func CassandraScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
case result := <-done:
|
case result := <-done:
|
||||||
err = result.err
|
err = result.err
|
||||||
if result.success && err == nil {
|
if result.success && err == nil {
|
||||||
resultChan <- nil
|
return nil
|
||||||
return
|
|
||||||
}
|
}
|
||||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
err = fmt.Errorf("连接超时")
|
err = fmt.Errorf("连接超时")
|
||||||
@ -99,14 +73,13 @@ func CassandraScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
// 处理错误情况
|
// 处理错误情况
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errlog := fmt.Sprintf("Cassandra服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
errlog := fmt.Sprintf("Cassandra服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
info.Host, info.Ports, user, pass, err)
|
||||||
Common.LogError(errlog)
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查是否需要重试
|
// 检查是否需要重试
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if retryCount == maxRetries-1 {
|
if retryCount == maxRetries-1 {
|
||||||
resultChan <- err
|
return err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
continue // 继续重试
|
continue // 继续重试
|
||||||
}
|
}
|
||||||
@ -115,24 +88,6 @@ func CassandraScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
break // 如果不需要重试,跳出重试循环
|
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
|
||||||
|
@ -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,43 +33,20 @@ 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
|
|
||||||
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) {
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
return fmt.Errorf("扫描超时")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 重试循环
|
||||||
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
// 执行连接尝试
|
// 执行连接尝试
|
||||||
done := make(chan struct {
|
done := make(chan struct {
|
||||||
success bool
|
success bool
|
||||||
@ -84,7 +59,7 @@ func ElasticScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
}{flag, err}
|
}{flag, err}
|
||||||
}(task.user, task.pass)
|
}(user, pass)
|
||||||
|
|
||||||
// 等待结果或超时
|
// 等待结果或超时
|
||||||
var err error
|
var err error
|
||||||
@ -92,8 +67,7 @@ func ElasticScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
case result := <-done:
|
case result := <-done:
|
||||||
err = result.err
|
err = result.err
|
||||||
if result.success && err == nil {
|
if result.success && err == nil {
|
||||||
resultChan <- nil
|
return nil
|
||||||
return
|
|
||||||
}
|
}
|
||||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
err = fmt.Errorf("连接超时")
|
err = fmt.Errorf("连接超时")
|
||||||
@ -102,14 +76,13 @@ func ElasticScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
// 处理错误情况
|
// 处理错误情况
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errlog := fmt.Sprintf("Elasticsearch服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
errlog := fmt.Sprintf("Elasticsearch服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
info.Host, info.Ports, user, pass, err)
|
||||||
Common.LogError(errlog)
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查是否需要重试
|
// 检查是否需要重试
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if retryCount == maxRetries-1 {
|
if retryCount == maxRetries-1 {
|
||||||
resultChan <- err
|
return err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
continue // 继续重试
|
continue // 继续重试
|
||||||
}
|
}
|
||||||
@ -118,24 +91,6 @@ func ElasticScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
break // 如果不需要重试,跳出重试循环
|
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
|
||||||
|
136
Plugins/FTP.go
136
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() {
|
|
||||||
defer close(taskChan)
|
|
||||||
for _, user := range Common.Userdict["ftp"] {
|
for _, user := range Common.Userdict["ftp"] {
|
||||||
for _, pass := range Common.Passwords {
|
for _, pass := range Common.Passwords {
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
pass = strings.Replace(pass, "{user}", user, -1)
|
||||||
taskChan <- struct {
|
|
||||||
user string
|
|
||||||
pass string
|
|
||||||
}{user, pass}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
// 检查是否超时
|
||||||
resultChan := make(chan error, threads)
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
|
return fmt.Errorf("扫描超时")
|
||||||
// 启动工作线程
|
|
||||||
for i := 0; i < threads; i++ {
|
|
||||||
wg.Add(1)
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
for task := range taskChan {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
resultChan <- nil
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重试循环
|
// 重试循环
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
|
// 执行FTP连接
|
||||||
done := make(chan struct {
|
done := make(chan struct {
|
||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
}, 1)
|
})
|
||||||
|
|
||||||
connCtx, connCancel := context.WithTimeout(ctx, time.Duration(Common.Timeout)*time.Second)
|
|
||||||
|
|
||||||
go func(user, pass string) {
|
go func(user, pass string) {
|
||||||
success, err := FtpConn(info, user, pass)
|
success, err := FtpConn(info, user, pass)
|
||||||
select {
|
done <- struct {
|
||||||
case <-connCtx.Done():
|
|
||||||
case done <- struct {
|
|
||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
}{success, err}:
|
}{success, err}
|
||||||
}
|
}(user, pass)
|
||||||
}(task.user, task.pass)
|
|
||||||
|
|
||||||
|
// 等待结果或超时
|
||||||
var err error
|
var err error
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
|
||||||
connCancel()
|
|
||||||
resultChan <- nil
|
|
||||||
return
|
|
||||||
case result := <-done:
|
case result := <-done:
|
||||||
err = result.err
|
err = result.err
|
||||||
if result.success && err == nil {
|
if result.success && err == nil {
|
||||||
successLog := fmt.Sprintf("FTP %v:%v %v %v",
|
return nil
|
||||||
info.Host, info.Ports, task.user, task.pass)
|
|
||||||
Common.LogSuccess(successLog)
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
cancel() // 取消所有操作
|
|
||||||
resultChan <- nil
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
case <-connCtx.Done():
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
err = fmt.Errorf("连接超时")
|
err = fmt.Errorf("连接超时")
|
||||||
}
|
}
|
||||||
|
|
||||||
connCancel()
|
// 处理错误情况
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
select {
|
errlog := fmt.Sprintf("[-] ftp %v:%v %v %v %v",
|
||||||
case <-ctx.Done():
|
info.Host, info.Ports, user, pass, err)
|
||||||
resultChan <- nil
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
errlog := fmt.Sprintf("ftp %v:%v %v %v %v",
|
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
|
||||||
Common.LogError(errlog)
|
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 retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if retryCount == maxRetries-1 {
|
if retryCount == maxRetries-1 {
|
||||||
continue
|
return err
|
||||||
}
|
}
|
||||||
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
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -18,43 +17,20 @@ 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++ {
|
|
||||||
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) {
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
return fmt.Errorf("扫描超时")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 重试循环
|
||||||
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
// 执行IMAP连接
|
// 执行IMAP连接
|
||||||
done := make(chan struct {
|
done := make(chan struct {
|
||||||
success bool
|
success bool
|
||||||
@ -67,7 +43,7 @@ func IMAPScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
}{success, err}
|
}{success, err}
|
||||||
}(task.user, task.pass)
|
}(user, pass)
|
||||||
|
|
||||||
// 等待结果或超时
|
// 等待结果或超时
|
||||||
var err error
|
var err error
|
||||||
@ -75,8 +51,7 @@ func IMAPScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
case result := <-done:
|
case result := <-done:
|
||||||
err = result.err
|
err = result.err
|
||||||
if result.success && err == nil {
|
if result.success && err == nil {
|
||||||
resultChan <- nil
|
return nil
|
||||||
return
|
|
||||||
}
|
}
|
||||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
err = fmt.Errorf("连接超时")
|
err = fmt.Errorf("连接超时")
|
||||||
@ -85,13 +60,12 @@ func IMAPScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
// 处理错误情况
|
// 处理错误情况
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errlog := fmt.Sprintf("IMAP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
errlog := fmt.Sprintf("IMAP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
info.Host, info.Ports, user, pass, err)
|
||||||
Common.LogError(errlog)
|
Common.LogError(errlog)
|
||||||
|
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if retryCount == maxRetries-1 {
|
if retryCount == maxRetries-1 {
|
||||||
resultChan <- err
|
return err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -100,22 +74,6 @@ func IMAPScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
break
|
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
|
||||||
|
@ -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,43 +30,20 @@ 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
|
|
||||||
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) {
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
return fmt.Errorf("扫描超时")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 重试循环
|
||||||
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
// 执行Kafka连接
|
// 执行Kafka连接
|
||||||
done := make(chan struct {
|
done := make(chan struct {
|
||||||
success bool
|
success bool
|
||||||
@ -82,7 +56,7 @@ func KafkaScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
}{success, err}
|
}{success, err}
|
||||||
}(task.user, task.pass)
|
}(user, pass)
|
||||||
|
|
||||||
// 等待结果或超时
|
// 等待结果或超时
|
||||||
var err error
|
var err error
|
||||||
@ -90,8 +64,7 @@ func KafkaScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
case result := <-done:
|
case result := <-done:
|
||||||
err = result.err
|
err = result.err
|
||||||
if result.success && err == nil {
|
if result.success && err == nil {
|
||||||
resultChan <- nil
|
return nil
|
||||||
return
|
|
||||||
}
|
}
|
||||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
err = fmt.Errorf("连接超时")
|
err = fmt.Errorf("连接超时")
|
||||||
@ -100,14 +73,13 @@ func KafkaScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
// 处理错误情况
|
// 处理错误情况
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errlog := fmt.Sprintf("Kafka服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
errlog := fmt.Sprintf("Kafka服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
info.Host, info.Ports, user, pass, err)
|
||||||
Common.LogError(errlog)
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查是否需要重试
|
// 检查是否需要重试
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if retryCount == maxRetries-1 {
|
if retryCount == maxRetries-1 {
|
||||||
resultChan <- err
|
return err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
continue // 继续重试
|
continue // 继续重试
|
||||||
}
|
}
|
||||||
@ -116,24 +88,6 @@ func KafkaScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
break // 如果不需要重试,跳出重试循环
|
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
|
||||||
|
@ -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,43 +22,20 @@ 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
|
|
||||||
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) {
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
return fmt.Errorf("扫描超时")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 重试循环
|
||||||
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
// 执行LDAP连接
|
// 执行LDAP连接
|
||||||
done := make(chan struct {
|
done := make(chan struct {
|
||||||
success bool
|
success bool
|
||||||
@ -73,7 +48,7 @@ func LDAPScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
}{success, err}
|
}{success, err}
|
||||||
}(task.user, task.pass)
|
}(user, pass)
|
||||||
|
|
||||||
// 等待结果或超时
|
// 等待结果或超时
|
||||||
var err error
|
var err error
|
||||||
@ -81,8 +56,7 @@ func LDAPScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
case result := <-done:
|
case result := <-done:
|
||||||
err = result.err
|
err = result.err
|
||||||
if result.success && err == nil {
|
if result.success && err == nil {
|
||||||
resultChan <- nil
|
return nil
|
||||||
return
|
|
||||||
}
|
}
|
||||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
err = fmt.Errorf("连接超时")
|
err = fmt.Errorf("连接超时")
|
||||||
@ -91,14 +65,13 @@ func LDAPScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
// 处理错误情况
|
// 处理错误情况
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errlog := fmt.Sprintf("LDAP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
errlog := fmt.Sprintf("LDAP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
info.Host, info.Ports, user, pass, err)
|
||||||
Common.LogError(errlog)
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查是否需要重试
|
// 检查是否需要重试
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if retryCount == maxRetries-1 {
|
if retryCount == maxRetries-1 {
|
||||||
resultChan <- err
|
return err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
continue // 继续重试
|
continue // 继续重试
|
||||||
}
|
}
|
||||||
@ -107,24 +80,6 @@ func LDAPScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
break // 如果不需要重试,跳出重试循环
|
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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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,43 +16,20 @@ 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++ {
|
|
||||||
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) {
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
return fmt.Errorf("扫描超时")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 重试循环
|
||||||
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
// 执行MSSQL连接
|
// 执行MSSQL连接
|
||||||
done := make(chan struct {
|
done := make(chan struct {
|
||||||
success bool
|
success bool
|
||||||
@ -66,7 +42,7 @@ func MssqlScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
}{success, err}
|
}{success, err}
|
||||||
}(task.user, task.pass)
|
}(user, pass)
|
||||||
|
|
||||||
// 等待结果或超时
|
// 等待结果或超时
|
||||||
var err error
|
var err error
|
||||||
@ -74,8 +50,7 @@ func MssqlScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
case result := <-done:
|
case result := <-done:
|
||||||
err = result.err
|
err = result.err
|
||||||
if result.success && err == nil {
|
if result.success && err == nil {
|
||||||
resultChan <- nil
|
return nil
|
||||||
return
|
|
||||||
}
|
}
|
||||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
err = fmt.Errorf("连接超时")
|
err = fmt.Errorf("连接超时")
|
||||||
@ -83,14 +58,13 @@ func MssqlScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errlog := fmt.Sprintf("MSSQL %v:%v %v %v %v",
|
errlog := fmt.Sprintf("MSSQL %v:%v %v %v %v",
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
info.Host, info.Ports, user, pass, err)
|
||||||
Common.LogError(errlog)
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查是否需要重试
|
// 检查是否需要重试
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if retryCount == maxRetries-1 {
|
if retryCount == maxRetries-1 {
|
||||||
resultChan <- err
|
return err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
continue // 继续重试
|
continue // 继续重试
|
||||||
}
|
}
|
||||||
@ -99,23 +73,6 @@ func MssqlScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
break // 如果不需要重试,跳出重试循环
|
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
|
||||||
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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,57 +16,20 @@ 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 {
|
|
||||||
// 检查是否已经成功
|
|
||||||
select {
|
|
||||||
case <-successChan:
|
|
||||||
resultChan <- nil
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重试循环
|
// 重试循环
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
// 检查是否超时
|
|
||||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 执行MySQL连接
|
// 执行MySQL连接
|
||||||
done := make(chan struct {
|
done := make(chan struct {
|
||||||
success bool
|
success bool
|
||||||
@ -80,7 +42,7 @@ func MysqlScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
}{success, err}
|
}{success, err}
|
||||||
}(task.user, task.pass)
|
}(user, pass)
|
||||||
|
|
||||||
// 等待结果或超时
|
// 等待结果或超时
|
||||||
var err error
|
var err error
|
||||||
@ -89,15 +51,10 @@ func MysqlScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
err = result.err
|
err = result.err
|
||||||
if result.success && err == nil {
|
if result.success && err == nil {
|
||||||
// 连接成功
|
// 连接成功
|
||||||
select {
|
|
||||||
case successChan <- struct{}{}: // 标记成功
|
|
||||||
successLog := fmt.Sprintf("MySQL %v:%v %v %v",
|
successLog := fmt.Sprintf("MySQL %v:%v %v %v",
|
||||||
info.Host, info.Ports, task.user, task.pass)
|
info.Host, info.Ports, user, pass)
|
||||||
Common.LogSuccess(successLog)
|
Common.LogSuccess(successLog)
|
||||||
default:
|
return nil
|
||||||
}
|
|
||||||
resultChan <- nil
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
err = fmt.Errorf("连接超时")
|
err = fmt.Errorf("连接超时")
|
||||||
@ -106,7 +63,7 @@ func MysqlScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
// 处理错误情况
|
// 处理错误情况
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errlog := fmt.Sprintf("MySQL %v:%v %v %v %v",
|
errlog := fmt.Sprintf("MySQL %v:%v %v %v %v",
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
info.Host, info.Ports, user, pass, err)
|
||||||
Common.LogError(errlog)
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 特殊处理认证失败的情况
|
// 特殊处理认证失败的情况
|
||||||
@ -117,8 +74,10 @@ func MysqlScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
// 检查是否需要重试
|
// 检查是否需要重试
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if retryCount == maxRetries-1 {
|
if retryCount == maxRetries-1 {
|
||||||
resultChan <- err
|
tmperr = err
|
||||||
return
|
if !strings.Contains(err.Error(), "Access denied") {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
continue // 继续重试
|
continue // 继续重试
|
||||||
}
|
}
|
||||||
@ -126,26 +85,6 @@ func MysqlScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resultChan <- nil
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 等待所有线程完成
|
|
||||||
go func() {
|
|
||||||
wg.Wait()
|
|
||||||
close(resultChan)
|
|
||||||
}()
|
|
||||||
|
|
||||||
// 检查结果
|
|
||||||
for err := range resultChan {
|
|
||||||
if err != nil {
|
|
||||||
tmperr = err
|
|
||||||
if !strings.Contains(err.Error(), "Access denied") {
|
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return tmperr
|
return tmperr
|
||||||
|
@ -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,43 +32,20 @@ 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
|
|
||||||
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) {
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
return fmt.Errorf("扫描超时")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 重试循环
|
||||||
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
// 执行Neo4j连接
|
// 执行Neo4j连接
|
||||||
done := make(chan struct {
|
done := make(chan struct {
|
||||||
success bool
|
success bool
|
||||||
@ -83,7 +58,7 @@ func Neo4jScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
}{flag, err}
|
}{flag, err}
|
||||||
}(task.user, task.pass)
|
}(user, pass)
|
||||||
|
|
||||||
// 等待结果或超时
|
// 等待结果或超时
|
||||||
var err error
|
var err error
|
||||||
@ -91,8 +66,7 @@ func Neo4jScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
case result := <-done:
|
case result := <-done:
|
||||||
err = result.err
|
err = result.err
|
||||||
if result.success && err == nil {
|
if result.success && err == nil {
|
||||||
resultChan <- nil
|
return nil
|
||||||
return
|
|
||||||
}
|
}
|
||||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
err = fmt.Errorf("连接超时")
|
err = fmt.Errorf("连接超时")
|
||||||
@ -101,14 +75,13 @@ func Neo4jScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
// 处理错误情况
|
// 处理错误情况
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errlog := fmt.Sprintf("Neo4j服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
errlog := fmt.Sprintf("Neo4j服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
info.Host, info.Ports, user, pass, err)
|
||||||
Common.LogError(errlog)
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查是否需要重试
|
// 检查是否需要重试
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if retryCount == maxRetries-1 {
|
if retryCount == maxRetries-1 {
|
||||||
resultChan <- err
|
return err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
continue // 继续重试
|
continue // 继续重试
|
||||||
}
|
}
|
||||||
@ -117,24 +90,6 @@ func Neo4jScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
break // 如果不需要重试,跳出重试循环
|
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
|
||||||
|
@ -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,45 +16,20 @@ 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
|
|
||||||
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) {
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
return fmt.Errorf("扫描超时")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 重试循环
|
||||||
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
// 执行Oracle连接
|
// 执行Oracle连接
|
||||||
done := make(chan struct {
|
done := make(chan struct {
|
||||||
success bool
|
success bool
|
||||||
@ -68,7 +42,7 @@ func OracleScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
}{success, err}
|
}{success, err}
|
||||||
}(task.user, task.pass)
|
}(user, pass)
|
||||||
|
|
||||||
// 等待结果或超时
|
// 等待结果或超时
|
||||||
var err error
|
var err error
|
||||||
@ -76,8 +50,7 @@ func OracleScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
case result := <-done:
|
case result := <-done:
|
||||||
err = result.err
|
err = result.err
|
||||||
if result.success && err == nil {
|
if result.success && err == nil {
|
||||||
resultChan <- nil
|
return nil
|
||||||
return
|
|
||||||
}
|
}
|
||||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
err = fmt.Errorf("连接超时")
|
err = fmt.Errorf("连接超时")
|
||||||
@ -86,14 +59,13 @@ func OracleScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
// 处理错误情况
|
// 处理错误情况
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errlog := fmt.Sprintf("Oracle %v:%v %v %v %v",
|
errlog := fmt.Sprintf("Oracle %v:%v %v %v %v",
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
info.Host, info.Ports, user, pass, err)
|
||||||
Common.LogError(errlog)
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查是否需要重试
|
// 检查是否需要重试
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if retryCount == maxRetries-1 {
|
if retryCount == maxRetries-1 {
|
||||||
resultChan <- err
|
return err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
continue // 继续重试
|
continue // 继续重试
|
||||||
}
|
}
|
||||||
@ -102,24 +74,6 @@ func OracleScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
break // 如果不需要重试,跳出重试循环
|
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
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -17,45 +16,20 @@ 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
|
|
||||||
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) {
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
return fmt.Errorf("扫描超时")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 重试循环
|
||||||
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
// 执行POP3连接
|
// 执行POP3连接
|
||||||
done := make(chan struct {
|
done := make(chan struct {
|
||||||
success bool
|
success bool
|
||||||
@ -68,7 +42,7 @@ func POP3Scan(info *Common.HostInfo) (tmperr error) {
|
|||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
}{success, err}
|
}{success, err}
|
||||||
}(task.user, task.pass)
|
}(user, pass)
|
||||||
|
|
||||||
// 等待结果或超时
|
// 等待结果或超时
|
||||||
var err error
|
var err error
|
||||||
@ -78,10 +52,9 @@ func POP3Scan(info *Common.HostInfo) (tmperr error) {
|
|||||||
if result.success && err == nil {
|
if result.success && err == nil {
|
||||||
// 连接成功
|
// 连接成功
|
||||||
successLog := fmt.Sprintf("POP3服务 %v:%v 用户名: %v 密码: %v",
|
successLog := fmt.Sprintf("POP3服务 %v:%v 用户名: %v 密码: %v",
|
||||||
info.Host, info.Ports, task.user, task.pass)
|
info.Host, info.Ports, user, pass)
|
||||||
Common.LogSuccess(successLog)
|
Common.LogSuccess(successLog)
|
||||||
resultChan <- nil
|
return nil
|
||||||
return
|
|
||||||
}
|
}
|
||||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
err = fmt.Errorf("连接超时")
|
err = fmt.Errorf("连接超时")
|
||||||
@ -90,14 +63,13 @@ func POP3Scan(info *Common.HostInfo) (tmperr error) {
|
|||||||
// 处理错误情况
|
// 处理错误情况
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errlog := fmt.Sprintf("POP3服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
errlog := fmt.Sprintf("POP3服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
info.Host, info.Ports, user, pass, err)
|
||||||
Common.LogError(errlog)
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查是否需要重试
|
// 检查是否需要重试
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if retryCount == maxRetries-1 {
|
if retryCount == maxRetries-1 {
|
||||||
resultChan <- err
|
return err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
continue // 继续重试
|
continue // 继续重试
|
||||||
}
|
}
|
||||||
@ -106,24 +78,6 @@ func POP3Scan(info *Common.HostInfo) (tmperr error) {
|
|||||||
break // 如果不需要重试,跳出重试循环
|
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
|
||||||
|
@ -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,45 +16,20 @@ 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
|
|
||||||
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) {
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
return fmt.Errorf("扫描超时")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 重试循环
|
||||||
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
// 执行PostgreSQL连接
|
// 执行PostgreSQL连接
|
||||||
done := make(chan struct {
|
done := make(chan struct {
|
||||||
success bool
|
success bool
|
||||||
@ -68,7 +42,7 @@ func PostgresScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
}{success, err}
|
}{success, err}
|
||||||
}(task.user, task.pass)
|
}(user, pass)
|
||||||
|
|
||||||
// 等待结果或超时
|
// 等待结果或超时
|
||||||
var err error
|
var err error
|
||||||
@ -76,8 +50,7 @@ func PostgresScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
case result := <-done:
|
case result := <-done:
|
||||||
err = result.err
|
err = result.err
|
||||||
if result.success && err == nil {
|
if result.success && err == nil {
|
||||||
resultChan <- nil
|
return nil
|
||||||
return
|
|
||||||
}
|
}
|
||||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
err = fmt.Errorf("连接超时")
|
err = fmt.Errorf("连接超时")
|
||||||
@ -86,14 +59,13 @@ func PostgresScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
// 处理错误情况
|
// 处理错误情况
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errlog := fmt.Sprintf("PostgreSQL %v:%v %v %v %v",
|
errlog := fmt.Sprintf("PostgreSQL %v:%v %v %v %v",
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
info.Host, info.Ports, user, pass, err)
|
||||||
Common.LogError(errlog)
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查是否需要重试
|
// 检查是否需要重试
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if retryCount == maxRetries-1 {
|
if retryCount == maxRetries-1 {
|
||||||
resultChan <- err
|
return err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
continue // 继续重试
|
continue // 继续重试
|
||||||
}
|
}
|
||||||
@ -102,24 +74,6 @@ func PostgresScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
break // 如果不需要重试,跳出重试循环
|
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
|
||||||
|
108
Plugins/RDP.go
108
Plugins/RDP.go
@ -37,36 +37,17 @@ 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() {
|
|
||||||
defer wg.Done()
|
|
||||||
for one := range brlist {
|
|
||||||
select {
|
|
||||||
case <-resultChan: // 检查是否已经找到有效凭据
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex.Lock()
|
|
||||||
num++
|
num++
|
||||||
mutex.Unlock()
|
pass = strings.Replace(pass, "{user}", user, -1)
|
||||||
|
|
||||||
user, pass := one.user, one.pass
|
// 尝试连接
|
||||||
flag, err := RdpConn(info.Host, Common.Domain, user, pass, port, Common.Timeout)
|
flag, err := RdpConn(info.Host, Common.Domain, user, pass, port, Common.Timeout)
|
||||||
|
|
||||||
if flag && err == nil {
|
if flag && err == nil {
|
||||||
@ -78,87 +59,16 @@ func RdpScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
result = fmt.Sprintf("RDP %v:%v:%v %v", info.Host, port, user, pass)
|
result = fmt.Sprintf("RDP %v:%v:%v %v", info.Host, port, user, pass)
|
||||||
}
|
}
|
||||||
Common.LogSuccess(result)
|
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() {
|
|
||||||
for _, user := range Common.Userdict["rdp"] {
|
|
||||||
for _, pass := range Common.Passwords {
|
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
|
||||||
select {
|
|
||||||
case <-resultChan: // 如果已经找到有效凭据,停止分发任务
|
|
||||||
return
|
|
||||||
case brlist <- Brutelist{user, pass}:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(brlist)
|
|
||||||
}()
|
|
||||||
|
|
||||||
// 等待任务完成或找到有效凭据
|
|
||||||
go func() {
|
|
||||||
wg.Wait()
|
|
||||||
close(resultChan)
|
|
||||||
}()
|
|
||||||
|
|
||||||
// 等待结果
|
|
||||||
if <-resultChan {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return tmperr
|
|
||||||
}
|
|
||||||
|
|
||||||
// worker RDP扫描工作协程
|
|
||||||
func worker(host, domain string, port int, wg *sync.WaitGroup, brlist chan Brutelist,
|
|
||||||
signal *bool, num *int, all int, mutex *sync.Mutex, timeout int64) {
|
|
||||||
defer wg.Done()
|
|
||||||
|
|
||||||
for one := range brlist {
|
|
||||||
if *signal {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
go incrNum(num, mutex)
|
|
||||||
|
|
||||||
user, pass := one.user, one.pass
|
|
||||||
flag, err := RdpConn(host, domain, user, pass, port, timeout)
|
|
||||||
|
|
||||||
if flag && err == nil {
|
|
||||||
// 连接成功
|
|
||||||
var result string
|
|
||||||
if domain != "" {
|
|
||||||
result = fmt.Sprintf("RDP %v:%v:%v\\%v %v", host, port, domain, user, pass)
|
|
||||||
} else {
|
|
||||||
result = fmt.Sprintf("RDP %v:%v:%v %v", host, port, user, pass)
|
|
||||||
}
|
|
||||||
Common.LogSuccess(result)
|
|
||||||
*signal = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 连接失败
|
// 连接失败
|
||||||
errlog := fmt.Sprintf("(%v/%v) RDP %v:%v %v %v %v", *num, all, host, port, user, pass, err)
|
errlog := fmt.Sprintf("(%v/%v) RDP %v:%v %v %v %v", num, total, info.Host, port, user, pass, err)
|
||||||
Common.LogError(errlog)
|
Common.LogError(errlog)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// incrNum 线程安全地增加计数器
|
return tmperr
|
||||||
func incrNum(num *int, mutex *sync.Mutex) {
|
|
||||||
mutex.Lock()
|
|
||||||
*num++
|
|
||||||
mutex.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RdpConn 尝试RDP连接
|
// RdpConn 尝试RDP连接
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -17,49 +16,14 @@ func RabbitMQScan(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["rabbitmq"])*len(Common.Passwords)+1) // +1 是为了加入guest账号
|
|
||||||
|
|
||||||
resultChan := make(chan error, threads)
|
|
||||||
|
|
||||||
// 先加入默认账号guest/guest
|
|
||||||
taskChan <- struct {
|
|
||||||
user string
|
|
||||||
pass string
|
|
||||||
}{"guest", "guest"}
|
|
||||||
|
|
||||||
// 生成其他用户名密码组合任务
|
|
||||||
for _, user := range Common.Userdict["rabbitmq"] {
|
|
||||||
for _, pass := range Common.Passwords {
|
|
||||||
pass = strings.Replace(pass, "{user}", user, -1)
|
|
||||||
taskChan <- struct {
|
|
||||||
user string
|
|
||||||
pass string
|
|
||||||
}{user, pass}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(taskChan)
|
|
||||||
|
|
||||||
// 启动工作线程
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
for i := 0; i < threads; i++ {
|
|
||||||
wg.Add(1)
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
starttime := time.Now().Unix()
|
starttime := time.Now().Unix()
|
||||||
|
|
||||||
for task := range taskChan {
|
// 先测试默认账号 guest/guest
|
||||||
// 重试循环
|
user, pass := "guest", "guest"
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
// 检查是否超时
|
// 检查是否超时
|
||||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
return fmt.Errorf("扫描超时")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 执行RabbitMQ连接
|
// 执行RabbitMQ连接
|
||||||
@ -68,13 +32,69 @@ func RabbitMQScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
err error
|
err error
|
||||||
})
|
})
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
success, err := RabbitMQConn(info, user, pass)
|
||||||
|
done <- struct {
|
||||||
|
success bool
|
||||||
|
err error
|
||||||
|
}{success, err}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 等待结果或超时
|
||||||
|
var err error
|
||||||
|
select {
|
||||||
|
case result := <-done:
|
||||||
|
err = result.err
|
||||||
|
if result.success && err == nil {
|
||||||
|
result := fmt.Sprintf("RabbitMQ服务 %v:%v 连接成功 用户名: %v 密码: %v",
|
||||||
|
info.Host, info.Ports, user, pass)
|
||||||
|
Common.LogSuccess(result)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
|
err = fmt.Errorf("连接超时")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
errlog := fmt.Sprintf("RabbitMQ服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
||||||
|
info.Host, info.Ports, user, pass, err)
|
||||||
|
Common.LogError(errlog)
|
||||||
|
|
||||||
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
|
if retryCount == maxRetries-1 {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历其他用户名密码组合
|
||||||
|
for _, user := range Common.Userdict["rabbitmq"] {
|
||||||
|
for _, pass := range Common.Passwords {
|
||||||
|
pass = strings.Replace(pass, "{user}", user, -1)
|
||||||
|
|
||||||
|
// 检查是否超时
|
||||||
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
|
return fmt.Errorf("扫描超时")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重试循环
|
||||||
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
|
// 执行RabbitMQ连接
|
||||||
|
done := make(chan struct {
|
||||||
|
success bool
|
||||||
|
err error
|
||||||
|
})
|
||||||
|
|
||||||
go func(user, pass string) {
|
go func(user, pass string) {
|
||||||
success, err := RabbitMQConn(info, user, pass)
|
success, err := RabbitMQConn(info, user, pass)
|
||||||
done <- struct {
|
done <- struct {
|
||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
}{success, err}
|
}{success, err}
|
||||||
}(task.user, task.pass)
|
}(user, pass)
|
||||||
|
|
||||||
// 等待结果或超时
|
// 等待结果或超时
|
||||||
var err error
|
var err error
|
||||||
@ -83,51 +103,28 @@ func RabbitMQScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
err = result.err
|
err = result.err
|
||||||
if result.success && err == nil {
|
if result.success && err == nil {
|
||||||
result := fmt.Sprintf("RabbitMQ服务 %v:%v 连接成功 用户名: %v 密码: %v",
|
result := fmt.Sprintf("RabbitMQ服务 %v:%v 连接成功 用户名: %v 密码: %v",
|
||||||
info.Host, info.Ports, task.user, task.pass)
|
info.Host, info.Ports, user, pass)
|
||||||
Common.LogSuccess(result)
|
Common.LogSuccess(result)
|
||||||
resultChan <- nil
|
return nil
|
||||||
return
|
|
||||||
}
|
}
|
||||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
err = fmt.Errorf("连接超时")
|
err = fmt.Errorf("连接超时")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理错误情况
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errlog := fmt.Sprintf("RabbitMQ服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
errlog := fmt.Sprintf("RabbitMQ服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
info.Host, info.Ports, user, pass, err)
|
||||||
Common.LogError(errlog)
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查是否需要重试
|
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if retryCount == maxRetries-1 {
|
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 err
|
||||||
}
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,43 +34,20 @@ 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
|
|
||||||
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) {
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
return fmt.Errorf("扫描超时")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 重试循环
|
||||||
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
// 执行Rsync连接
|
// 执行Rsync连接
|
||||||
done := make(chan struct {
|
done := make(chan struct {
|
||||||
success bool
|
success bool
|
||||||
@ -85,7 +60,7 @@ func RsyncScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
}{flag && err == nil, err}
|
}{flag && err == nil, err}
|
||||||
}(task.user, task.pass)
|
}(user, pass)
|
||||||
|
|
||||||
// 等待结果或超时
|
// 等待结果或超时
|
||||||
var err error
|
var err error
|
||||||
@ -93,8 +68,7 @@ func RsyncScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
case result := <-done:
|
case result := <-done:
|
||||||
err = result.err
|
err = result.err
|
||||||
if result.success {
|
if result.success {
|
||||||
resultChan <- nil
|
return nil
|
||||||
return
|
|
||||||
}
|
}
|
||||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
err = fmt.Errorf("连接超时")
|
err = fmt.Errorf("连接超时")
|
||||||
@ -103,14 +77,13 @@ func RsyncScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
// 处理错误情况
|
// 处理错误情况
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errlog := fmt.Sprintf("Rsync服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
errlog := fmt.Sprintf("Rsync服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
info.Host, info.Ports, user, pass, err)
|
||||||
Common.LogError(errlog)
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查是否需要重试
|
// 检查是否需要重试
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if retryCount == maxRetries-1 {
|
if retryCount == maxRetries-1 {
|
||||||
resultChan <- err
|
return err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
continue // 继续重试
|
continue // 继续重试
|
||||||
}
|
}
|
||||||
@ -119,24 +92,6 @@ func RsyncScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
break // 如果不需要重试,跳出重试循环
|
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
|
||||||
|
@ -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)
|
|
||||||
go func(username string) {
|
|
||||||
defer wg.Done()
|
|
||||||
for pass := range taskChan {
|
|
||||||
select {
|
|
||||||
case <-successChan:
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
success, err := doWithTimeOut(info, username, pass)
|
|
||||||
if success {
|
if success {
|
||||||
if Common.Domain != "" {
|
if Common.Domain != "" {
|
||||||
Common.LogSuccess(fmt.Sprintf("SMB认证成功 %s:%s %s\\%s:%s",
|
Common.LogSuccess(fmt.Sprintf("SMB认证成功 %s:%s %s\\%s:%s",
|
||||||
info.Host, info.Ports, Common.Domain, username, pass))
|
info.Host, info.Ports, Common.Domain, user, pass))
|
||||||
} else {
|
} else {
|
||||||
Common.LogSuccess(fmt.Sprintf("SMB认证成功 %s:%s %s:%s",
|
Common.LogSuccess(fmt.Sprintf("SMB认证成功 %s:%s %s:%s",
|
||||||
info.Host, info.Ports, username, pass))
|
info.Host, info.Ports, user, pass))
|
||||||
}
|
}
|
||||||
successChan <- struct{}{}
|
return nil
|
||||||
|
|
||||||
// 成功后等待确保日志打印完成
|
|
||||||
time.Sleep(500 * time.Millisecond)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Common.LogError(fmt.Sprintf("SMB认证失败 %s:%s %s:%s %v",
|
Common.LogError(fmt.Sprintf("SMB认证失败 %s:%s %s:%s %v",
|
||||||
info.Host, info.Ports, username, pass, err))
|
info.Host, info.Ports, user, pass, err))
|
||||||
|
|
||||||
// 等待失败日志打印完成
|
// 等待失败日志打印完成
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|
||||||
if strings.Contains(err.Error(), "账号锁定") {
|
if strings.Contains(err.Error(), "账号锁定") {
|
||||||
for range taskChan {
|
// 账号锁定时跳过当前用户的剩余密码
|
||||||
// 清空通道
|
break // 跳出密码循环,继续下一个用户
|
||||||
}
|
|
||||||
time.Sleep(200 * time.Millisecond) // 确保锁定日志打印完成
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}(user)
|
|
||||||
}
|
|
||||||
|
|
||||||
wg.Wait()
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-successChan:
|
|
||||||
// 等待日志打印完成
|
|
||||||
time.Sleep(500 * time.Millisecond)
|
|
||||||
Common.LogWG.Wait()
|
|
||||||
return nil
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 主函数结束前多等待一会
|
|
||||||
time.Sleep(500 * time.Millisecond)
|
|
||||||
Common.LogWG.Wait()
|
|
||||||
// 最后再等待一下,确保所有日志都打印完成
|
|
||||||
time.Sleep(500 * time.Millisecond)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
129
Plugins/SMB2.go
129
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,78 +26,39 @@ 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++ {
|
|
||||||
wg.Add(1)
|
|
||||||
go func(username string) {
|
|
||||||
defer wg.Done()
|
|
||||||
|
|
||||||
for pass := range taskChan {
|
|
||||||
select {
|
|
||||||
case <-successChan:
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重试循环
|
// 重试循环
|
||||||
for retryCount := 0; retryCount < Common.MaxRetries; retryCount++ {
|
for retryCount := 0; retryCount < Common.MaxRetries; retryCount++ {
|
||||||
hasPrintMutex.Lock()
|
success, err, printed := Smb2Con(info, user, pass, []byte{}, hasprint)
|
||||||
currentHasPrint := hasprint
|
|
||||||
hasPrintMutex.Unlock()
|
|
||||||
|
|
||||||
success, err, printed := Smb2Con(info, username, pass, []byte{}, currentHasPrint)
|
|
||||||
|
|
||||||
if printed {
|
if printed {
|
||||||
hasPrintMutex.Lock()
|
|
||||||
hasprint = true
|
hasprint = true
|
||||||
hasPrintMutex.Unlock()
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if success {
|
if success {
|
||||||
logSuccessfulAuth(info, username, pass, []byte{})
|
logSuccessfulAuth(info, user, pass, []byte{})
|
||||||
time.Sleep(100 * time.Millisecond)
|
return nil
|
||||||
successChan <- struct{}{}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logFailedAuth(info, username, pass, []byte{}, err)
|
logFailedAuth(info, user, pass, []byte{}, err)
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
|
|
||||||
// 检查是否账户锁定
|
// 检查是否账户锁定
|
||||||
if strings.Contains(err.Error(), "user account has been automatically locked") {
|
if strings.Contains(err.Error(), "user account has been automatically locked") {
|
||||||
// 发现账户锁定,清空任务通道并返回
|
// 账户锁定,跳过该用户的剩余密码
|
||||||
for range taskChan {
|
break
|
||||||
// 清空通道
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 其他登录失败情况
|
// 其他登录失败情况
|
||||||
@ -117,20 +77,8 @@ func smbPasswordScan(info *Common.HostInfo) error {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}(user)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Wait() // 等待当前用户的所有密码尝试完成
|
|
||||||
|
|
||||||
// 检查是否已经找到正确密码
|
|
||||||
select {
|
|
||||||
case <-successChan:
|
|
||||||
return nil
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
time.Sleep(200 * time.Millisecond)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,66 +87,32 @@ 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
|
|
||||||
}
|
|
||||||
close(taskChan)
|
|
||||||
|
|
||||||
// 启动工作线程
|
|
||||||
for i := 0; i < threads; i++ {
|
|
||||||
wg.Add(1)
|
|
||||||
go func(username string) {
|
|
||||||
defer wg.Done()
|
|
||||||
|
|
||||||
for hash := range taskChan {
|
|
||||||
select {
|
|
||||||
case <-successChan:
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重试循环
|
// 重试循环
|
||||||
for retryCount := 0; retryCount < Common.MaxRetries; retryCount++ {
|
for retryCount := 0; retryCount < Common.MaxRetries; retryCount++ {
|
||||||
hasPrintMutex.Lock()
|
success, err, printed := Smb2Con(info, user, "", hash, hasprint)
|
||||||
currentHasPrint := hasprint
|
|
||||||
hasPrintMutex.Unlock()
|
|
||||||
|
|
||||||
success, err, printed := Smb2Con(info, username, "", hash, currentHasPrint)
|
|
||||||
|
|
||||||
if printed {
|
if printed {
|
||||||
hasPrintMutex.Lock()
|
|
||||||
hasprint = true
|
hasprint = true
|
||||||
hasPrintMutex.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if success {
|
if success {
|
||||||
logSuccessfulAuth(info, username, "", hash)
|
logSuccessfulAuth(info, user, "", hash)
|
||||||
successChan <- struct{}{}
|
return nil
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logFailedAuth(info, username, "", hash, err)
|
logFailedAuth(info, user, "", hash, err)
|
||||||
|
|
||||||
// 检查是否账户锁定
|
// 检查是否账户锁定
|
||||||
if strings.Contains(err.Error(), "user account has been automatically locked") {
|
if strings.Contains(err.Error(), "user account has been automatically locked") {
|
||||||
// 发现账户锁定,清空任务通道并返回
|
// 账户锁定,跳过该用户的剩余hash
|
||||||
for range taskChan {
|
break
|
||||||
// 清空通道
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 其他登录失败情况
|
// 其他登录失败情况
|
||||||
@ -217,17 +131,6 @@ func smbHashScan(info *Common.HostInfo) error {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}(user)
|
|
||||||
}
|
|
||||||
|
|
||||||
wg.Wait() // 等待当前用户的所有hash尝试完成
|
|
||||||
|
|
||||||
// 检查是否已经找到正确凭据
|
|
||||||
select {
|
|
||||||
case <-successChan:
|
|
||||||
return nil
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -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,43 +34,20 @@ 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
|
|
||||||
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) {
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
return fmt.Errorf("扫描超时")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 重试循环
|
||||||
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
// 执行SMTP连接
|
// 执行SMTP连接
|
||||||
done := make(chan struct {
|
done := make(chan struct {
|
||||||
success bool
|
success bool
|
||||||
@ -85,7 +60,7 @@ func SmtpScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
}{flag, err}
|
}{flag, err}
|
||||||
}(task.user, task.pass)
|
}(user, pass)
|
||||||
|
|
||||||
// 等待结果或超时
|
// 等待结果或超时
|
||||||
var err error
|
var err error
|
||||||
@ -93,8 +68,7 @@ func SmtpScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
case result := <-done:
|
case result := <-done:
|
||||||
err = result.err
|
err = result.err
|
||||||
if result.success && err == nil {
|
if result.success && err == nil {
|
||||||
resultChan <- nil
|
return nil
|
||||||
return
|
|
||||||
}
|
}
|
||||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
err = fmt.Errorf("连接超时")
|
err = fmt.Errorf("连接超时")
|
||||||
@ -103,14 +77,13 @@ func SmtpScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
// 处理错误情况
|
// 处理错误情况
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errlog := fmt.Sprintf("SMTP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
errlog := fmt.Sprintf("SMTP服务 %v:%v 尝试失败 用户名: %v 密码: %v 错误: %v",
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
info.Host, info.Ports, user, pass, err)
|
||||||
Common.LogError(errlog)
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查是否需要重试
|
// 检查是否需要重试
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if retryCount == maxRetries-1 {
|
if retryCount == maxRetries-1 {
|
||||||
resultChan <- err
|
return err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
continue // 继续重试
|
continue // 继续重试
|
||||||
}
|
}
|
||||||
@ -119,24 +92,6 @@ func SmtpScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
break // 如果不需要重试,跳出重试循环
|
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
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -17,39 +16,20 @@ 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"}
|
||||||
|
|
||||||
// 创建任务通道
|
|
||||||
taskChan := make(chan string, len(defaultCommunities))
|
|
||||||
resultChan := make(chan error, threads)
|
|
||||||
|
|
||||||
// 生成所有community任务
|
|
||||||
for _, community := range defaultCommunities {
|
|
||||||
taskChan <- community
|
|
||||||
}
|
|
||||||
close(taskChan)
|
|
||||||
|
|
||||||
// 启动工作线程
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
for i := 0; i < threads; i++ {
|
|
||||||
wg.Add(1)
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
starttime := time.Now().Unix()
|
starttime := time.Now().Unix()
|
||||||
|
timeout := time.Duration(Common.Timeout) * time.Second
|
||||||
|
|
||||||
|
// 遍历所有 community
|
||||||
|
for _, community := range defaultCommunities {
|
||||||
|
// 检查是否超时
|
||||||
|
if time.Now().Unix()-starttime > int64(timeout.Seconds()) {
|
||||||
|
return fmt.Errorf("扫描超时")
|
||||||
|
}
|
||||||
|
|
||||||
for community := range taskChan {
|
|
||||||
// 重试循环
|
// 重试循环
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
// 检查是否超时
|
|
||||||
timeout := time.Duration(Common.Timeout) * time.Second
|
|
||||||
if time.Now().Unix()-starttime > int64(timeout.Seconds()) {
|
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 执行SNMP连接
|
// 执行SNMP连接
|
||||||
done := make(chan struct {
|
done := make(chan struct {
|
||||||
success bool
|
success bool
|
||||||
@ -74,8 +54,7 @@ func SNMPScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
successLog := fmt.Sprintf("SNMP服务 %v:%v community: %v 连接成功",
|
successLog := fmt.Sprintf("SNMP服务 %v:%v community: %v 连接成功",
|
||||||
info.Host, info.Ports, community)
|
info.Host, info.Ports, community)
|
||||||
Common.LogSuccess(successLog)
|
Common.LogSuccess(successLog)
|
||||||
resultChan <- nil
|
return nil
|
||||||
return
|
|
||||||
}
|
}
|
||||||
case <-time.After(timeout):
|
case <-time.After(timeout):
|
||||||
err = fmt.Errorf("连接超时")
|
err = fmt.Errorf("连接超时")
|
||||||
@ -90,8 +69,7 @@ func SNMPScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
// 检查是否需要重试
|
// 检查是否需要重试
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if retryCount == maxRetries-1 {
|
if retryCount == maxRetries-1 {
|
||||||
resultChan <- err
|
return err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
continue // 继续重试
|
continue // 继续重试
|
||||||
}
|
}
|
||||||
@ -100,25 +78,6 @@ func SNMPScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
break // 如果不需要重试,跳出重试循环
|
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
|
||||||
}
|
}
|
||||||
|
102
Plugins/SSH.go
102
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,98 +17,68 @@ 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++ {
|
|
||||||
wg.Add(1)
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
for task := range taskChan {
|
|
||||||
// 重试循环
|
// 重试循环
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(Common.Timeout)*time.Second)
|
||||||
done := make(chan struct {
|
done := make(chan struct {
|
||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
})
|
}, 1)
|
||||||
|
|
||||||
go func(user, pass string) {
|
go func(user, pass string) {
|
||||||
success, err := SshConn(info, user, pass)
|
success, err := SshConn(info, user, pass)
|
||||||
done <- struct {
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
case done <- struct {
|
||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
}{success, err}
|
}{success, err}:
|
||||||
}(task.user, task.pass)
|
}
|
||||||
|
}(user, pass)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
select {
|
select {
|
||||||
case result := <-done:
|
case result := <-done:
|
||||||
err = result.err
|
err = result.err
|
||||||
if result.success {
|
if result.success {
|
||||||
resultChan <- nil
|
successLog := fmt.Sprintf("SSH认证成功 %v:%v User:%v Pass:%v",
|
||||||
return
|
info.Host, info.Ports, user, pass)
|
||||||
|
Common.LogSuccess(successLog)
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
cancel()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
case <-ctx.Done():
|
||||||
err = fmt.Errorf("连接超时")
|
err = fmt.Errorf("连接超时")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cancel()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errlog := fmt.Sprintf("SSH认证失败 %v:%v User:%v Pass:%v Err:%v",
|
errlog := fmt.Sprintf("SSH认证失败 %v:%v User:%v Pass:%v Err:%v",
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
info.Host, info.Ports, user, pass, err)
|
||||||
Common.LogError(errlog)
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查是否是已知错误,如果是则等待3秒后重试
|
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if retryCount == maxRetries-1 {
|
if retryCount == maxRetries-1 {
|
||||||
resultChan <- err
|
return err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
continue // 继续重试
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if Common.SshKeyPath != "" {
|
if Common.SshKeyPath != "" {
|
||||||
resultChan <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
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 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,45 +18,20 @@ 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
|
|
||||||
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) {
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
return fmt.Errorf("扫描超时")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 重试循环
|
||||||
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
// 执行Telnet连接
|
// 执行Telnet连接
|
||||||
done := make(chan struct {
|
done := make(chan struct {
|
||||||
success bool
|
success bool
|
||||||
@ -72,7 +46,7 @@ func TelnetScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
noAuth bool
|
noAuth bool
|
||||||
err error
|
err error
|
||||||
}{err == nil, flag, err}
|
}{err == nil, flag, err}
|
||||||
}(task.user, task.pass)
|
}(user, pass)
|
||||||
|
|
||||||
// 等待结果或超时
|
// 等待结果或超时
|
||||||
var err error
|
var err error
|
||||||
@ -84,15 +58,13 @@ func TelnetScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
result := fmt.Sprintf("Telnet服务 %v:%v 无需认证",
|
result := fmt.Sprintf("Telnet服务 %v:%v 无需认证",
|
||||||
info.Host, info.Ports)
|
info.Host, info.Ports)
|
||||||
Common.LogSuccess(result)
|
Common.LogSuccess(result)
|
||||||
resultChan <- nil
|
return nil
|
||||||
return
|
|
||||||
} else if result.success {
|
} else if result.success {
|
||||||
// 成功爆破
|
// 成功爆破
|
||||||
result := fmt.Sprintf("Telnet服务 %v:%v 用户名:%v 密码:%v",
|
result := fmt.Sprintf("Telnet服务 %v:%v 用户名:%v 密码:%v",
|
||||||
info.Host, info.Ports, task.user, task.pass)
|
info.Host, info.Ports, user, pass)
|
||||||
Common.LogSuccess(result)
|
Common.LogSuccess(result)
|
||||||
resultChan <- nil
|
return nil
|
||||||
return
|
|
||||||
}
|
}
|
||||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
err = fmt.Errorf("连接超时")
|
err = fmt.Errorf("连接超时")
|
||||||
@ -101,14 +73,13 @@ func TelnetScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
// 处理错误情况
|
// 处理错误情况
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errlog := fmt.Sprintf("Telnet连接失败 %v:%v 用户名:%v 密码:%v 错误:%v",
|
errlog := fmt.Sprintf("Telnet连接失败 %v:%v 用户名:%v 密码:%v 错误:%v",
|
||||||
info.Host, info.Ports, task.user, task.pass, err)
|
info.Host, info.Ports, user, pass, err)
|
||||||
Common.LogError(errlog)
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查是否需要重试
|
// 检查是否需要重试
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if retryCount == maxRetries-1 {
|
if retryCount == maxRetries-1 {
|
||||||
resultChan <- err
|
return err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
continue // 继续重试
|
continue // 继续重试
|
||||||
}
|
}
|
||||||
@ -117,24 +88,6 @@ func TelnetScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
break // 如果不需要重试,跳出重试循环
|
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,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("认证失败")
|
|
||||||
}
|
|
@ -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,36 +15,18 @@ func VncScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
maxRetries := Common.MaxRetries
|
maxRetries := Common.MaxRetries
|
||||||
threads := Common.BruteThreads
|
|
||||||
modename := "vnc"
|
modename := "vnc"
|
||||||
|
|
||||||
// 创建任务通道
|
|
||||||
taskChan := make(chan string, len(Common.Passwords))
|
|
||||||
resultChan := make(chan error, threads)
|
|
||||||
|
|
||||||
// 生成所有密码任务
|
|
||||||
for _, pass := range Common.Passwords {
|
|
||||||
taskChan <- 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()
|
starttime := time.Now().Unix()
|
||||||
|
|
||||||
for pass := range taskChan {
|
// 遍历所有密码
|
||||||
// 重试循环
|
for _, pass := range Common.Passwords {
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
|
||||||
// 检查是否超时
|
// 检查是否超时
|
||||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
return fmt.Errorf("扫描超时")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 重试循环
|
||||||
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
// 执行VNC连接
|
// 执行VNC连接
|
||||||
done := make(chan struct {
|
done := make(chan struct {
|
||||||
success bool
|
success bool
|
||||||
@ -70,8 +51,7 @@ func VncScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
successLog := fmt.Sprintf("%s://%v:%v 密码: %v",
|
successLog := fmt.Sprintf("%s://%v:%v 密码: %v",
|
||||||
modename, info.Host, info.Ports, pass)
|
modename, info.Host, info.Ports, pass)
|
||||||
Common.LogSuccess(successLog)
|
Common.LogSuccess(successLog)
|
||||||
resultChan <- nil
|
return nil
|
||||||
return
|
|
||||||
}
|
}
|
||||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
err = fmt.Errorf("连接超时")
|
err = fmt.Errorf("连接超时")
|
||||||
@ -86,8 +66,7 @@ func VncScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
// 检查是否是需要重试的错误
|
// 检查是否是需要重试的错误
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if retryCount == maxRetries-1 {
|
if retryCount == maxRetries-1 {
|
||||||
resultChan <- err
|
return err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
continue // 继续重试
|
continue // 继续重试
|
||||||
}
|
}
|
||||||
@ -96,25 +75,6 @@ func VncScan(info *Common.HostInfo) (tmperr error) {
|
|||||||
break // 如果不需要重试,跳出重试循环
|
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
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -34,48 +33,20 @@ 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
|
|
||||||
}{user, pass}
|
|
||||||
// 如果是32位hash值,只尝试一次密码
|
|
||||||
if len(Common.HashValue) == 32 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(taskChan)
|
|
||||||
|
|
||||||
// 启动工作线程
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
for i := 0; i < threads; i++ {
|
|
||||||
wg.Add(1)
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
starttime := time.Now().Unix()
|
|
||||||
|
|
||||||
for task := range taskChan {
|
|
||||||
// 重试循环
|
|
||||||
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
|
||||||
// 检查是否超时
|
// 检查是否超时
|
||||||
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
if time.Now().Unix()-starttime > int64(Common.Timeout) {
|
||||||
resultChan <- fmt.Errorf("扫描超时")
|
return fmt.Errorf("扫描超时")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 重试循环
|
||||||
|
for retryCount := 0; retryCount < maxRetries; retryCount++ {
|
||||||
// 执行WMI连接
|
// 执行WMI连接
|
||||||
done := make(chan struct {
|
done := make(chan struct {
|
||||||
success bool
|
success bool
|
||||||
@ -88,7 +59,7 @@ func WmiExec(info *Common.HostInfo) (tmperr error) {
|
|||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
}{success, err}
|
}{success, err}
|
||||||
}(task.user, task.pass)
|
}(user, pass)
|
||||||
|
|
||||||
// 等待结果或超时
|
// 等待结果或超时
|
||||||
var err error
|
var err error
|
||||||
@ -99,21 +70,20 @@ func WmiExec(info *Common.HostInfo) (tmperr error) {
|
|||||||
// 成功连接
|
// 成功连接
|
||||||
var successLog string
|
var successLog string
|
||||||
if Common.Domain != "" {
|
if Common.Domain != "" {
|
||||||
successLog = fmt.Sprintf("[+] WmiExec %v:%v:%v\\%v ",
|
successLog = fmt.Sprintf("WmiExec %v:%v:%v\\%v ",
|
||||||
info.Host, info.Ports, Common.Domain, task.user)
|
info.Host, info.Ports, Common.Domain, user)
|
||||||
} else {
|
} else {
|
||||||
successLog = fmt.Sprintf("[+] WmiExec %v:%v:%v ",
|
successLog = fmt.Sprintf("WmiExec %v:%v:%v ",
|
||||||
info.Host, info.Ports, task.user)
|
info.Host, info.Ports, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
if Common.HashValue != "" {
|
if Common.HashValue != "" {
|
||||||
successLog += "hash: " + Common.HashValue
|
successLog += "hash: " + Common.HashValue
|
||||||
} else {
|
} else {
|
||||||
successLog += task.pass
|
successLog += pass
|
||||||
}
|
}
|
||||||
Common.LogSuccess(successLog)
|
Common.LogSuccess(successLog)
|
||||||
resultChan <- nil
|
return nil
|
||||||
return
|
|
||||||
}
|
}
|
||||||
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
case <-time.After(time.Duration(Common.Timeout) * time.Second):
|
||||||
err = fmt.Errorf("连接超时")
|
err = fmt.Errorf("连接超时")
|
||||||
@ -121,16 +91,15 @@ func WmiExec(info *Common.HostInfo) (tmperr error) {
|
|||||||
|
|
||||||
// 处理错误情况
|
// 处理错误情况
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errlog := fmt.Sprintf("[-] WmiExec %v:%v %v %v %v",
|
errlog := fmt.Sprintf("WmiExec %v:%v %v %v %v",
|
||||||
info.Host, 445, task.user, task.pass, err)
|
info.Host, 445, user, pass, err)
|
||||||
errlog = strings.Replace(errlog, "\n", "", -1)
|
errlog = strings.Replace(errlog, "\n", "", -1)
|
||||||
Common.LogError(errlog)
|
Common.LogError(errlog)
|
||||||
|
|
||||||
// 检查是否需要重试
|
// 检查是否需要重试
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
||||||
if retryCount == maxRetries-1 {
|
if retryCount == maxRetries-1 {
|
||||||
resultChan <- err
|
return err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
continue // 继续重试
|
continue // 继续重试
|
||||||
}
|
}
|
||||||
@ -138,23 +107,10 @@ func WmiExec(info *Common.HostInfo) (tmperr error) {
|
|||||||
|
|
||||||
break // 如果不需要重试,跳出重试循环
|
break // 如果不需要重试,跳出重试循环
|
||||||
}
|
}
|
||||||
}
|
|
||||||
resultChan <- nil
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 等待所有线程完成
|
// 如果是32位hash值,只尝试一次密码
|
||||||
go func() {
|
if len(Common.HashValue) == 32 {
|
||||||
wg.Wait()
|
break
|
||||||
close(resultChan)
|
|
||||||
}()
|
|
||||||
|
|
||||||
// 检查结果
|
|
||||||
for err := range resultChan {
|
|
||||||
if err != nil {
|
|
||||||
tmperr = err
|
|
||||||
if retryErr := Common.CheckErrs(err); retryErr != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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