mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 14:06:44 +08:00
fix: 修复进度条显示错位问题,实现真正的固定底部进度条
- 简化进度条定位逻辑,移除复杂的光标定位操作 - 优化LogWithProgress协调机制,确保日志与进度条正确交互 - 修复ANSI转义序列被直接输出的问题 - 进度条现在能够在底部原地更新,不再与日志输出争抢显示空间
This commit is contained in:
parent
9b6c389ea8
commit
c8038bdc62
430
Common/Bridge.go
430
Common/Bridge.go
@ -1,430 +0,0 @@
|
|||||||
package common
|
|
||||||
|
|
||||||
/*
|
|
||||||
Bridge.go - 统一桥接模块
|
|
||||||
|
|
||||||
将Config.go、Log.go、Output.go、Proxy.go的桥接功能合并到一个文件中,
|
|
||||||
减少文件数量,提高代码组织性。保持所有原有API的完全兼容性。
|
|
||||||
*/
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/tls"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/fatih/color"
|
|
||||||
"github.com/schollz/progressbar/v3"
|
|
||||||
|
|
||||||
"github.com/shadow1ng/fscan/common/config"
|
|
||||||
"github.com/shadow1ng/fscan/common/i18n"
|
|
||||||
"github.com/shadow1ng/fscan/common/logging"
|
|
||||||
"github.com/shadow1ng/fscan/common/output"
|
|
||||||
"github.com/shadow1ng/fscan/common/proxy"
|
|
||||||
)
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 配置桥接 (Config.go 功能)
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
var version = "2.0.2"
|
|
||||||
|
|
||||||
// 向后兼容的输出配置变量
|
|
||||||
var (
|
|
||||||
Outputfile string
|
|
||||||
OutputFormat string
|
|
||||||
ProgressBar *progressbar.ProgressBar
|
|
||||||
OutputMutex sync.Mutex
|
|
||||||
)
|
|
||||||
|
|
||||||
// PocInfo POC详细信息结构
|
|
||||||
type PocInfo = config.PocInfo
|
|
||||||
|
|
||||||
func syncOutputConfig() {
|
|
||||||
cfg := config.GetGlobalConfig()
|
|
||||||
if cfg != nil && cfg.Output != nil {
|
|
||||||
Outputfile = cfg.Output.Outputfile
|
|
||||||
OutputFormat = cfg.Output.OutputFormat
|
|
||||||
}
|
|
||||||
ProgressBar = config.GetGlobalProgressBar()
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 日志桥接 (Log.go 功能)
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// 全局日志状态和变量
|
|
||||||
var (
|
|
||||||
status = logging.NewScanStatus()
|
|
||||||
Num, End int64
|
|
||||||
StartTime = time.Now()
|
|
||||||
globalLogger *logging.Logger
|
|
||||||
loggerMutex sync.Mutex
|
|
||||||
)
|
|
||||||
|
|
||||||
// 日志级别常量
|
|
||||||
const (
|
|
||||||
LogLevelAll = string(logging.LevelAll)
|
|
||||||
LogLevelError = string(logging.LevelError)
|
|
||||||
LogLevelBase = string(logging.LevelBase)
|
|
||||||
LogLevelInfo = string(logging.LevelInfo)
|
|
||||||
LogLevelSuccess = string(logging.LevelSuccess)
|
|
||||||
LogLevelDebug = string(logging.LevelDebug)
|
|
||||||
LogLevelInfoSuccess = string(logging.LevelInfoSuccess)
|
|
||||||
LogLevelBaseInfoSuccess = string(logging.LevelBaseInfoSuccess)
|
|
||||||
)
|
|
||||||
|
|
||||||
// 类型别名
|
|
||||||
type LogEntry = logging.LogEntry
|
|
||||||
type ScanStatus = logging.ScanStatus
|
|
||||||
type ProgressDisplay = logging.ProgressDisplay
|
|
||||||
|
|
||||||
func getGlobalLogger() *logging.Logger {
|
|
||||||
loggerMutex.Lock()
|
|
||||||
defer loggerMutex.Unlock()
|
|
||||||
|
|
||||||
if globalLogger == nil {
|
|
||||||
// 获取正确的日志级别 - 动态获取确保使用最新值
|
|
||||||
level := getLogLevelFromString(LogLevel)
|
|
||||||
|
|
||||||
config := &logging.LoggerConfig{
|
|
||||||
Level: level, EnableColor: !NoColor, SlowOutput: SlowLogOutput,
|
|
||||||
ShowProgress: true, StartTime: StartTime,
|
|
||||||
LevelColors: map[logging.LogLevel]color.Attribute{
|
|
||||||
logging.LevelError: color.FgBlue, logging.LevelBase: color.FgYellow,
|
|
||||||
logging.LevelInfo: color.FgGreen, logging.LevelSuccess: color.FgRed, logging.LevelDebug: color.FgWhite,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
globalLogger = logging.NewLogger(config)
|
|
||||||
if ProgressBar != nil {
|
|
||||||
globalLogger.SetProgressBar(ProgressBar)
|
|
||||||
}
|
|
||||||
globalLogger.SetOutputMutex(&OutputMutex)
|
|
||||||
status = globalLogger.GetScanStatus()
|
|
||||||
}
|
|
||||||
return globalLogger
|
|
||||||
}
|
|
||||||
|
|
||||||
// shouldLogLevel 检查是否应该记录该级别的日志
|
|
||||||
func shouldLogLevel(logger *logging.Logger, level logging.LogLevel) bool {
|
|
||||||
// 直接基于当前的LogLevel配置判断
|
|
||||||
switch LogLevel {
|
|
||||||
case "all", "ALL":
|
|
||||||
return true
|
|
||||||
case "error", "ERROR":
|
|
||||||
return level == logging.LevelError
|
|
||||||
case "base", "BASE":
|
|
||||||
return level == logging.LevelBase
|
|
||||||
case "info", "INFO":
|
|
||||||
return level == logging.LevelInfo
|
|
||||||
case "success", "SUCCESS":
|
|
||||||
return level == logging.LevelSuccess
|
|
||||||
case "debug", "DEBUG":
|
|
||||||
return level == logging.LevelDebug || level == logging.LevelError
|
|
||||||
case "info,success", "INFO_SUCCESS":
|
|
||||||
return level == logging.LevelInfo || level == logging.LevelSuccess
|
|
||||||
case "base,info,success", "BASE_INFO_SUCCESS":
|
|
||||||
return level == logging.LevelBase || level == logging.LevelInfo || level == logging.LevelSuccess
|
|
||||||
default:
|
|
||||||
// 默认使用BaseInfoSuccess级别,不包含DEBUG和ERROR级别
|
|
||||||
return level == logging.LevelBase || level == logging.LevelInfo || level == logging.LevelSuccess
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// getLogLevelFromString 根据字符串获取日志级别
|
|
||||||
func getLogLevelFromString(levelStr string) logging.LogLevel {
|
|
||||||
switch levelStr {
|
|
||||||
case "all", "ALL":
|
|
||||||
return logging.LevelAll
|
|
||||||
case "error", "ERROR":
|
|
||||||
return logging.LevelError
|
|
||||||
case "base", "BASE":
|
|
||||||
return logging.LevelBase
|
|
||||||
case "info", "INFO":
|
|
||||||
return logging.LevelInfo
|
|
||||||
case "success", "SUCCESS":
|
|
||||||
return logging.LevelSuccess
|
|
||||||
case "debug", "DEBUG":
|
|
||||||
return logging.LevelDebug
|
|
||||||
case "info,success":
|
|
||||||
return logging.LevelInfoSuccess
|
|
||||||
case "base,info,success", "BASE_INFO_SUCCESS":
|
|
||||||
return logging.LevelBaseInfoSuccess
|
|
||||||
default:
|
|
||||||
// 默认使用InfoSuccess级别,只显示Info和Success消息
|
|
||||||
return logging.LevelInfoSuccess
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 日志相关函数
|
|
||||||
func InitLogger() {
|
|
||||||
// 重置全局logger以确保使用最新的LogLevel配置
|
|
||||||
loggerMutex.Lock()
|
|
||||||
globalLogger = nil
|
|
||||||
loggerMutex.Unlock()
|
|
||||||
|
|
||||||
log.SetOutput(io.Discard)
|
|
||||||
getGlobalLogger().Initialize()
|
|
||||||
}
|
|
||||||
func LogDebug(msg string) { logWithProgressCoordination(msg, "debug") }
|
|
||||||
func LogBase(msg string) { logWithProgressCoordination(msg, "base") }
|
|
||||||
func LogInfo(msg string) { logWithProgressCoordination(msg, "info") }
|
|
||||||
func LogSuccess(result string) { logWithProgressCoordination(result, "success") }
|
|
||||||
func LogError(errMsg string) { logWithProgressCoordination(errMsg, "error") }
|
|
||||||
func CheckErrs(err error) error { return logging.CheckErrs(err) }
|
|
||||||
|
|
||||||
// logWithProgressCoordination 协调日志输出与进度条的冲突
|
|
||||||
func logWithProgressCoordination(msg, level string) {
|
|
||||||
logger := getGlobalLogger()
|
|
||||||
|
|
||||||
// 首先检查是否应该记录这个级别的日志
|
|
||||||
var logLevel logging.LogLevel
|
|
||||||
switch level {
|
|
||||||
case "debug":
|
|
||||||
logLevel = logging.LevelDebug
|
|
||||||
case "base":
|
|
||||||
logLevel = logging.LevelBase
|
|
||||||
case "info":
|
|
||||||
logLevel = logging.LevelInfo
|
|
||||||
case "success":
|
|
||||||
logLevel = logging.LevelSuccess
|
|
||||||
case "error":
|
|
||||||
logLevel = logging.LevelError
|
|
||||||
default:
|
|
||||||
logLevel = logging.LevelDebug
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果当前日志级别不应该显示这条消息,直接返回
|
|
||||||
if !shouldLogLevel(logger, logLevel) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果进度条活跃,使用协调输出
|
|
||||||
if IsProgressActive() {
|
|
||||||
// 简单格式化消息,保持时间戳格式一致
|
|
||||||
elapsed := time.Since(StartTime)
|
|
||||||
var prefix, colorCode, resetCode string
|
|
||||||
|
|
||||||
if !NoColor {
|
|
||||||
resetCode = "\033[0m"
|
|
||||||
switch level {
|
|
||||||
case "debug":
|
|
||||||
colorCode = "\033[37m" // 白色
|
|
||||||
prefix = " "
|
|
||||||
case "base":
|
|
||||||
colorCode = "\033[33m" // 黄色
|
|
||||||
prefix = " "
|
|
||||||
case "info":
|
|
||||||
colorCode = "\033[32m" // 绿色
|
|
||||||
prefix = " [*] "
|
|
||||||
case "success":
|
|
||||||
colorCode = "\033[31m" // 红色
|
|
||||||
prefix = " [+] "
|
|
||||||
case "error":
|
|
||||||
colorCode = "\033[34m" // 蓝色
|
|
||||||
prefix = " [-] "
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch level {
|
|
||||||
case "info":
|
|
||||||
prefix = " [*] "
|
|
||||||
case "success":
|
|
||||||
prefix = " [+] "
|
|
||||||
case "error":
|
|
||||||
prefix = " [-] "
|
|
||||||
default:
|
|
||||||
prefix = " "
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
formattedMsg := fmt.Sprintf("[%.1fs]%s%s%s%s",
|
|
||||||
elapsed.Seconds(), prefix, colorCode, msg, resetCode)
|
|
||||||
LogWithProgress(formattedMsg)
|
|
||||||
} else {
|
|
||||||
// 如果进度条不活跃,使用原始日志方法
|
|
||||||
switch level {
|
|
||||||
case "debug":
|
|
||||||
logger.Debug(msg)
|
|
||||||
case "base":
|
|
||||||
logger.Base(msg)
|
|
||||||
case "info":
|
|
||||||
logger.Info(msg)
|
|
||||||
case "success":
|
|
||||||
logger.Success(msg)
|
|
||||||
case "error":
|
|
||||||
logger.Error(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 输出桥接 (Output.go 功能)
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// 全局输出管理器
|
|
||||||
var ResultOutput *OutputManager
|
|
||||||
|
|
||||||
type OutputManager struct{ manager *output.Manager }
|
|
||||||
type ResultType = output.ResultType
|
|
||||||
|
|
||||||
const (
|
|
||||||
HOST ResultType = output.TypeHost
|
|
||||||
PORT ResultType = output.TypePort
|
|
||||||
SERVICE ResultType = output.TypeService
|
|
||||||
VULN ResultType = output.TypeVuln
|
|
||||||
)
|
|
||||||
|
|
||||||
type ScanResult = output.ScanResult
|
|
||||||
|
|
||||||
func createOutputManager(outputPath, outputFormat string) (*OutputManager, error) {
|
|
||||||
var format output.OutputFormat
|
|
||||||
switch outputFormat {
|
|
||||||
case "txt":
|
|
||||||
format = output.FormatTXT
|
|
||||||
case "json":
|
|
||||||
format = output.FormatJSON
|
|
||||||
case "csv":
|
|
||||||
format = output.FormatCSV
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf(i18n.GetText("output_format_invalid", outputFormat))
|
|
||||||
}
|
|
||||||
|
|
||||||
config := output.DefaultManagerConfig(outputPath, format)
|
|
||||||
manager, err := output.NewManager(config)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &OutputManager{manager: manager}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 输出相关函数
|
|
||||||
func InitOutput() error {
|
|
||||||
LogDebug(i18n.GetText("output_init_start"))
|
|
||||||
switch OutputFormat {
|
|
||||||
case "txt", "json", "csv":
|
|
||||||
default:
|
|
||||||
return fmt.Errorf(i18n.GetText("output_format_invalid", OutputFormat))
|
|
||||||
}
|
|
||||||
if Outputfile == "" {
|
|
||||||
return fmt.Errorf(i18n.GetText("output_path_empty"))
|
|
||||||
}
|
|
||||||
|
|
||||||
manager, err := createOutputManager(Outputfile, OutputFormat)
|
|
||||||
if err != nil {
|
|
||||||
LogDebug(i18n.GetText("output_init_failed", err))
|
|
||||||
return fmt.Errorf(i18n.GetText("output_init_failed", err))
|
|
||||||
}
|
|
||||||
ResultOutput = manager
|
|
||||||
output.SetGlobalManager(manager.manager)
|
|
||||||
LogDebug(i18n.GetText("output_init_success"))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (om *OutputManager) saveResult(result *ScanResult) error {
|
|
||||||
if om.manager == nil {
|
|
||||||
return fmt.Errorf(i18n.GetText("output_not_init"))
|
|
||||||
}
|
|
||||||
LogDebug(i18n.GetText("output_saving_result", result.Type, result.Target))
|
|
||||||
return om.manager.SaveResult(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SaveResult(result *ScanResult) error {
|
|
||||||
if ResultOutput == nil {
|
|
||||||
LogDebug(i18n.GetText("output_not_init"))
|
|
||||||
return fmt.Errorf(i18n.GetText("output_not_init"))
|
|
||||||
}
|
|
||||||
return ResultOutput.saveResult(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func CloseOutput() error {
|
|
||||||
if ResultOutput == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
LogDebug(i18n.GetText("output_closing"))
|
|
||||||
err := ResultOutput.manager.Close()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf(i18n.GetText("output_close_failed", err))
|
|
||||||
}
|
|
||||||
LogDebug(i18n.GetText("output_closed"))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 代理桥接 (Proxy.go 功能)
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// 代理相关函数
|
|
||||||
func WrapperTcpWithTimeout(network, address string, timeout time.Duration) (net.Conn, error) {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
|
||||||
defer cancel()
|
|
||||||
return proxy.DialContextWithProxy(ctx, network, address)
|
|
||||||
}
|
|
||||||
|
|
||||||
func WrapperTcpWithContext(ctx context.Context, network, address string) (net.Conn, error) {
|
|
||||||
return proxy.DialContextWithProxy(ctx, network, address)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Socks5Dialer(forward *net.Dialer) (interface{}, error) {
|
|
||||||
if err := syncProxyConfig(); err != nil {
|
|
||||||
return nil, fmt.Errorf(i18n.GetText("socks5_create_failed", err))
|
|
||||||
}
|
|
||||||
manager := proxy.GetGlobalProxy()
|
|
||||||
dialer, err := manager.GetDialer()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf(i18n.GetText("socks5_create_failed", err))
|
|
||||||
}
|
|
||||||
return dialer, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func WrapperTlsWithContext(ctx context.Context, network, address string, tlsConfig *tls.Config) (net.Conn, error) {
|
|
||||||
if err := syncProxyConfig(); err != nil {
|
|
||||||
LogError(i18n.GetText("proxy_config_sync_failed", err.Error()))
|
|
||||||
}
|
|
||||||
conn, err := proxy.DialTLSContextWithProxy(ctx, network, address, tlsConfig)
|
|
||||||
if err != nil {
|
|
||||||
LogError(i18n.GetText("tls_conn_failed", err.Error()))
|
|
||||||
return nil, fmt.Errorf(i18n.GetText("tls_conn_failed", err))
|
|
||||||
}
|
|
||||||
return conn, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func syncProxyConfig() error {
|
|
||||||
var proxyURL string
|
|
||||||
if Socks5Proxy != "" {
|
|
||||||
proxyURL = Socks5Proxy
|
|
||||||
} else if HttpProxy != "" {
|
|
||||||
proxyURL = HttpProxy
|
|
||||||
}
|
|
||||||
|
|
||||||
if proxy.IsProxyEnabledGlobally() {
|
|
||||||
currentAddr := proxy.GetGlobalProxyAddress()
|
|
||||||
if (proxyURL == "" && currentAddr == "") ||
|
|
||||||
(proxyURL != "" && currentAddr != "" && (Socks5Proxy == currentAddr || HttpProxy == currentAddr)) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := proxy.InitGlobalProxy(proxyURL); err != nil {
|
|
||||||
return fmt.Errorf(i18n.GetText("proxy_init_failed", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
if proxyURL != "" {
|
|
||||||
LogBase(i18n.GetText("proxy_enabled", proxy.GetGlobalProxyType(), proxy.GetGlobalProxyAddress()))
|
|
||||||
} else {
|
|
||||||
LogBase(i18n.GetText("proxy_disabled"))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 初始化函数
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
config.SetGlobalVersion(version)
|
|
||||||
syncOutputConfig()
|
|
||||||
}
|
|
@ -42,10 +42,10 @@ var (
|
|||||||
LocalMode bool // 本地模式
|
LocalMode bool // 本地模式
|
||||||
|
|
||||||
// 基础认证配置
|
// 基础认证配置
|
||||||
Username string // 用户名
|
Username string // 用户名
|
||||||
Password string // 密码
|
Password string // 密码
|
||||||
Userdict map[string][]string // 用户字典
|
Userdict map[string][]string // 用户字典
|
||||||
Passwords []string // 密码列表
|
Passwords []string // 密码列表
|
||||||
|
|
||||||
// 网络配置
|
// 网络配置
|
||||||
HttpProxy string // HTTP代理
|
HttpProxy string // HTTP代理
|
||||||
@ -130,4 +130,4 @@ func SetThreadNum(num int) {
|
|||||||
// init 自动初始化
|
// init 自动初始化
|
||||||
func init() {
|
func init() {
|
||||||
InitGlobalConfig()
|
InitGlobalConfig()
|
||||||
}
|
}
|
||||||
|
@ -131,6 +131,9 @@ func Parse(Info *HostInfo) error {
|
|||||||
// 显示解析结果摘要
|
// 显示解析结果摘要
|
||||||
showParseSummary(result.Config)
|
showParseSummary(result.Config)
|
||||||
|
|
||||||
|
// 同步变量到core包
|
||||||
|
syncToCore()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -498,6 +501,9 @@ func applyLogLevel() {
|
|||||||
newLogger.SetProgressBar(ProgressBar)
|
newLogger.SetProgressBar(ProgressBar)
|
||||||
}
|
}
|
||||||
newLogger.SetOutputMutex(&OutputMutex)
|
newLogger.SetOutputMutex(&OutputMutex)
|
||||||
|
|
||||||
|
// 设置协调输出函数,使用LogWithProgress
|
||||||
|
newLogger.SetCoordinatedOutput(LogWithProgress)
|
||||||
|
|
||||||
// 更新全局日志管理器
|
// 更新全局日志管理器
|
||||||
globalLogger = newLogger
|
globalLogger = newLogger
|
||||||
|
@ -72,6 +72,9 @@ func (pm *ProgressManager) InitProgress(total int64, description string) {
|
|||||||
pm.isActive = true
|
pm.isActive = true
|
||||||
pm.enabled = true
|
pm.enabled = true
|
||||||
|
|
||||||
|
// 为进度条保留空间
|
||||||
|
pm.setupProgressSpace()
|
||||||
|
|
||||||
// 初始显示进度条
|
// 初始显示进度条
|
||||||
pm.renderProgress()
|
pm.renderProgress()
|
||||||
}
|
}
|
||||||
@ -130,24 +133,23 @@ func (pm *ProgressManager) FinishProgress() {
|
|||||||
pm.isActive = false
|
pm.isActive = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// reserveProgressSpace 为进度条保留底部空间
|
// setupProgressSpace 设置进度条空间
|
||||||
func (pm *ProgressManager) reserveProgressSpace() {
|
func (pm *ProgressManager) setupProgressSpace() {
|
||||||
if pm.terminalHeight <= 0 {
|
// 简化设计:进度条在原地更新,不需要预留额外空间
|
||||||
return
|
// 只是标记进度条开始的位置
|
||||||
}
|
pm.lastContentLine = 0
|
||||||
|
}
|
||||||
// 移动到底部保留区域上方
|
|
||||||
targetLine := pm.terminalHeight - pm.reservedLines
|
// moveToContentArea 移动到内容输出区域
|
||||||
fmt.Printf("\033[%d;1H", targetLine)
|
func (pm *ProgressManager) moveToContentArea() {
|
||||||
|
// 对于简化的实现,直接在当前位置输出内容
|
||||||
// 在底部创建空行
|
// 不需要复杂的光标移动
|
||||||
for i := 0; i < pm.reservedLines; i++ {
|
}
|
||||||
fmt.Println()
|
|
||||||
}
|
// moveToProgressLine 移动到进度条位置
|
||||||
|
func (pm *ProgressManager) moveToProgressLine() {
|
||||||
// 回到内容输出位置
|
// 移动到行首准备重绘进度条
|
||||||
fmt.Printf("\033[%d;1H", targetLine)
|
fmt.Print("\r")
|
||||||
pm.lastContentLine = targetLine - 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// renderProgress 渲染进度条(使用锁避免输出冲突)
|
// renderProgress 渲染进度条(使用锁避免输出冲突)
|
||||||
@ -155,9 +157,6 @@ func (pm *ProgressManager) renderProgress() {
|
|||||||
pm.outputMutex.Lock()
|
pm.outputMutex.Lock()
|
||||||
defer pm.outputMutex.Unlock()
|
defer pm.outputMutex.Unlock()
|
||||||
|
|
||||||
// 清除当前行并回到行首
|
|
||||||
fmt.Print("\033[2K\r")
|
|
||||||
|
|
||||||
pm.renderProgressUnsafe()
|
pm.renderProgressUnsafe()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,13 +307,13 @@ func LogWithProgress(message string) {
|
|||||||
pm.outputMutex.Lock()
|
pm.outputMutex.Lock()
|
||||||
defer pm.outputMutex.Unlock()
|
defer pm.outputMutex.Unlock()
|
||||||
|
|
||||||
// 清除当前进度条
|
// 清除当前行(清除进度条)
|
||||||
fmt.Print("\033[2K\r")
|
fmt.Print("\033[2K\r")
|
||||||
|
|
||||||
// 输出消息
|
// 输出日志消息
|
||||||
fmt.Println(message)
|
fmt.Println(message)
|
||||||
|
|
||||||
// 重新绘制进度条
|
// 重绘进度条
|
||||||
pm.renderProgressUnsafe()
|
pm.renderProgressUnsafe()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,6 +323,9 @@ func (pm *ProgressManager) renderProgressUnsafe() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 移动到行首并清除当前行
|
||||||
|
fmt.Print("\033[2K\r")
|
||||||
|
|
||||||
// 生成进度条内容
|
// 生成进度条内容
|
||||||
progressBar := pm.generateProgressBar()
|
progressBar := pm.generateProgressBar()
|
||||||
|
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
package common
|
|
||||||
|
|
||||||
import "github.com/shadow1ng/fscan/common/core"
|
|
||||||
|
|
||||||
/*
|
|
||||||
Types.go - 类型定义(向后兼容层)
|
|
||||||
|
|
||||||
此文件保持向后兼容,实际类型定义和插件系统已迁移到Core/Plugin.go
|
|
||||||
*/
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 向后兼容的类型别名
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// HostInfo 主机信息结构 - 引用Core包中的定义
|
|
||||||
type HostInfo = core.HostInfo
|
|
||||||
|
|
||||||
// ScanPlugin 扫描插件结构 - 引用Core包中的定义
|
|
||||||
type ScanPlugin = core.ScanPlugin
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 向后兼容的插件类型常量
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
const (
|
|
||||||
PluginTypeService = core.PluginTypeService // 服务类型插件
|
|
||||||
PluginTypeWeb = core.PluginTypeWeb // Web类型插件
|
|
||||||
PluginTypeLocal = core.PluginTypeLocal // 本地类型插件
|
|
||||||
PluginTypeBrute = core.PluginTypeBrute // 暴力破解插件
|
|
||||||
PluginTypePoc = core.PluginTypePoc // POC验证插件
|
|
||||||
PluginTypeScan = core.PluginTypeScan // 扫描探测插件
|
|
||||||
)
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 向后兼容的插件管理函数
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// RegisterPlugin 注册插件到全局管理器 - 保持向后兼容
|
|
||||||
func RegisterPlugin(name string, plugin ScanPlugin) {
|
|
||||||
if err := core.RegisterPlugin(name, plugin); err != nil {
|
|
||||||
// 注册失败时记录错误,但不中断程序
|
|
||||||
LogError("Failed to register plugin " + name + ": " + err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetGlobalPluginManager 获取全局插件管理器
|
|
||||||
func GetGlobalPluginManager() *core.PluginManager {
|
|
||||||
return core.GetGlobalPluginManager()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 向后兼容的全局变量 - 引用Core包中的定义
|
|
||||||
var PluginManager = core.LegacyPluginManager
|
|
@ -1,97 +0,0 @@
|
|||||||
package common
|
|
||||||
|
|
||||||
import "github.com/shadow1ng/fscan/common/core"
|
|
||||||
|
|
||||||
/*
|
|
||||||
Variables.go - 全局变量(向后兼容层)
|
|
||||||
|
|
||||||
此文件保持向后兼容,实际变量管理已迁移到Core/Manager.go
|
|
||||||
建议新代码使用Core.GetGlobalConfigManager()获取配置管理器
|
|
||||||
*/
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 向后兼容的全局变量 - 直接引用Core包中的定义
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// 核心扫描配置
|
|
||||||
var (
|
|
||||||
ScanMode = core.ScanMode // 扫描模式
|
|
||||||
ThreadNum = core.ThreadNum // 线程数
|
|
||||||
Timeout = core.Timeout // 超时时间
|
|
||||||
DisablePing = core.DisablePing // 禁用ping
|
|
||||||
LocalMode = core.LocalMode // 本地模式
|
|
||||||
)
|
|
||||||
|
|
||||||
// 基础认证配置
|
|
||||||
var (
|
|
||||||
Username = core.Username // 用户名
|
|
||||||
Password = core.Password // 密码
|
|
||||||
Userdict = core.Userdict // 用户字典
|
|
||||||
Passwords = core.Passwords // 密码列表
|
|
||||||
)
|
|
||||||
|
|
||||||
// 网络配置
|
|
||||||
var (
|
|
||||||
HttpProxy = core.HttpProxy // HTTP代理
|
|
||||||
Socks5Proxy = core.Socks5Proxy // SOCKS5代理
|
|
||||||
)
|
|
||||||
|
|
||||||
// 显示控制
|
|
||||||
var (
|
|
||||||
NoColor = core.NoColor // 禁用颜色
|
|
||||||
Language = core.Language // 语言
|
|
||||||
LogLevel = core.LogLevel // 日志级别
|
|
||||||
)
|
|
||||||
|
|
||||||
// 端口映射
|
|
||||||
var (
|
|
||||||
PortMap = core.PortMap // 端口映射
|
|
||||||
DefaultMap = core.DefaultMap // 默认映射
|
|
||||||
)
|
|
||||||
|
|
||||||
// 输出配置 (已在Bridge.go中定义,此处不重复声明)
|
|
||||||
// var Outputfile, OutputFormat
|
|
||||||
|
|
||||||
// 其他全局状态 (已在Flag.go中定义,此处不重复声明)
|
|
||||||
// var SlowLogOutput
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 向后兼容的访问函数
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// GetGlobalConfigManager 获取全局配置管理器(已废弃)
|
|
||||||
// 注意:ConfigManager 已被移除,此函数不再可用
|
|
||||||
// func GetGlobalConfigManager() *core.ConfigManager {
|
|
||||||
// return core.GetGlobalConfigManager()
|
|
||||||
// }
|
|
||||||
|
|
||||||
// InitGlobalConfig 初始化全局配置
|
|
||||||
func InitGlobalConfig() {
|
|
||||||
core.InitGlobalConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetScanMode 获取扫描模式
|
|
||||||
func GetScanMode() string {
|
|
||||||
return core.GetScanMode()
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetScanMode 设置扫描模式
|
|
||||||
func SetScanMode(mode string) {
|
|
||||||
core.SetScanMode(mode)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetThreadNum 获取线程数
|
|
||||||
func GetThreadNum() int {
|
|
||||||
return core.GetThreadNum()
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetThreadNum 设置线程数
|
|
||||||
func SetThreadNum(num int) {
|
|
||||||
core.SetThreadNum(num)
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 向后兼容的日志级别常量 (已在Bridge.go中定义,此处不重复声明)
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// const LogLevelAll, LogLevelError, etc. - 已在Bridge.go中定义
|
|
202
Common/common.go
Normal file
202
Common/common.go
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
/*
|
||||||
|
common.go - 简化的统一入口
|
||||||
|
|
||||||
|
移除所有向后兼容层,提供清晰的模块化接口。
|
||||||
|
直接导出各子模块的核心功能,避免代码债务。
|
||||||
|
*/
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/shadow1ng/fscan/common/core"
|
||||||
|
"github.com/shadow1ng/fscan/common/logging"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
|
)
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 核心类型导出 - 直接从core模块导出
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
type HostInfo = core.HostInfo
|
||||||
|
type ScanPlugin = core.ScanPlugin
|
||||||
|
|
||||||
|
// 插件类型常量
|
||||||
|
const (
|
||||||
|
PluginTypeService = core.PluginTypeService
|
||||||
|
PluginTypeWeb = core.PluginTypeWeb
|
||||||
|
PluginTypeLocal = core.PluginTypeLocal
|
||||||
|
PluginTypeBrute = core.PluginTypeBrute
|
||||||
|
PluginTypePoc = core.PluginTypePoc
|
||||||
|
PluginTypeScan = core.PluginTypeScan
|
||||||
|
)
|
||||||
|
|
||||||
|
// 全局插件管理器
|
||||||
|
var PluginManager = core.LegacyPluginManager
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 核心功能导出 - 直接调用对应模块
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// 插件系统
|
||||||
|
func RegisterPlugin(name string, plugin ScanPlugin) {
|
||||||
|
if err := core.RegisterPlugin(name, plugin); err != nil {
|
||||||
|
LogError("Failed to register plugin " + name + ": " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetGlobalPluginManager() *core.PluginManager {
|
||||||
|
return core.GetGlobalPluginManager()
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 日志系统简化接口
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
var globalLogger *logging.Logger
|
||||||
|
var loggerMutex sync.Mutex
|
||||||
|
|
||||||
|
func getGlobalLogger() *logging.Logger {
|
||||||
|
loggerMutex.Lock()
|
||||||
|
defer loggerMutex.Unlock()
|
||||||
|
|
||||||
|
if globalLogger == nil {
|
||||||
|
level := getLogLevelFromString(LogLevel)
|
||||||
|
config := &logging.LoggerConfig{
|
||||||
|
Level: level,
|
||||||
|
EnableColor: !NoColor,
|
||||||
|
SlowOutput: SlowLogOutput,
|
||||||
|
ShowProgress: true,
|
||||||
|
StartTime: StartTime,
|
||||||
|
}
|
||||||
|
globalLogger = logging.NewLogger(config)
|
||||||
|
if ProgressBar != nil {
|
||||||
|
globalLogger.SetProgressBar(ProgressBar)
|
||||||
|
}
|
||||||
|
globalLogger.SetOutputMutex(&OutputMutex)
|
||||||
|
|
||||||
|
// 设置协调输出函数,使用LogWithProgress
|
||||||
|
globalLogger.SetCoordinatedOutput(LogWithProgress)
|
||||||
|
}
|
||||||
|
return globalLogger
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLogLevelFromString(levelStr string) logging.LogLevel {
|
||||||
|
switch levelStr {
|
||||||
|
case "all", "ALL":
|
||||||
|
return logging.LevelAll
|
||||||
|
case "error", "ERROR":
|
||||||
|
return logging.LevelError
|
||||||
|
case "base", "BASE":
|
||||||
|
return logging.LevelBase
|
||||||
|
case "info", "INFO":
|
||||||
|
return logging.LevelInfo
|
||||||
|
case "success", "SUCCESS":
|
||||||
|
return logging.LevelSuccess
|
||||||
|
case "debug", "DEBUG":
|
||||||
|
return logging.LevelDebug
|
||||||
|
case "info,success":
|
||||||
|
return logging.LevelInfoSuccess
|
||||||
|
case "base,info,success", "BASE_INFO_SUCCESS":
|
||||||
|
return logging.LevelBaseInfoSuccess
|
||||||
|
default:
|
||||||
|
return logging.LevelInfoSuccess
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 日志函数
|
||||||
|
func InitLogger() {
|
||||||
|
loggerMutex.Lock()
|
||||||
|
globalLogger = nil
|
||||||
|
loggerMutex.Unlock()
|
||||||
|
getGlobalLogger().Initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
func LogDebug(msg string) { getGlobalLogger().Debug(msg) }
|
||||||
|
func LogBase(msg string) { getGlobalLogger().Base(msg) }
|
||||||
|
func LogInfo(msg string) { getGlobalLogger().Info(msg) }
|
||||||
|
func LogSuccess(result string) { getGlobalLogger().Success(result) }
|
||||||
|
func LogError(errMsg string) { getGlobalLogger().Error(errMsg) }
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 输出系统简化接口
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
var ResultOutput *output.Manager
|
||||||
|
|
||||||
|
func InitOutput() error {
|
||||||
|
if Outputfile == "" {
|
||||||
|
return fmt.Errorf("output file not specified")
|
||||||
|
}
|
||||||
|
|
||||||
|
var format output.OutputFormat
|
||||||
|
switch OutputFormat {
|
||||||
|
case "txt":
|
||||||
|
format = output.FormatTXT
|
||||||
|
case "json":
|
||||||
|
format = output.FormatJSON
|
||||||
|
case "csv":
|
||||||
|
format = output.FormatCSV
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid output format: %s", OutputFormat)
|
||||||
|
}
|
||||||
|
|
||||||
|
config := output.DefaultManagerConfig(Outputfile, format)
|
||||||
|
manager, err := output.NewManager(config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ResultOutput = manager
|
||||||
|
output.SetGlobalManager(manager)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CloseOutput() error {
|
||||||
|
if ResultOutput == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return ResultOutput.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func SaveResult(result *output.ScanResult) error {
|
||||||
|
if ResultOutput == nil {
|
||||||
|
return fmt.Errorf("output not initialized")
|
||||||
|
}
|
||||||
|
return ResultOutput.SaveResult(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 网络连接辅助函数
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// WrapperTcpWithTimeout TCP连接包装器,带超时
|
||||||
|
func WrapperTcpWithTimeout(network, address string, timeout time.Duration) (net.Conn, error) {
|
||||||
|
return net.DialTimeout(network, address, timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WrapperTcpWithContext TCP连接包装器,带上下文
|
||||||
|
func WrapperTcpWithContext(ctx context.Context, network, address string) (net.Conn, error) {
|
||||||
|
var d net.Dialer
|
||||||
|
return d.DialContext(ctx, network, address)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WrapperTlsWithContext TLS连接包装器,带上下文
|
||||||
|
func WrapperTlsWithContext(ctx context.Context, network, address string, config *tls.Config) (net.Conn, error) {
|
||||||
|
d := &tls.Dialer{Config: config}
|
||||||
|
return d.DialContext(ctx, network, address)
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 错误处理辅助函数
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// CheckErrs 检查单个错误 - 简化版本
|
||||||
|
func CheckErrs(err error) error {
|
||||||
|
return err
|
||||||
|
}
|
169
Common/globals.go
Normal file
169
Common/globals.go
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/schollz/progressbar/v3"
|
||||||
|
"github.com/shadow1ng/fscan/common/core"
|
||||||
|
"github.com/shadow1ng/fscan/common/logging"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
globals.go - 全局变量定义
|
||||||
|
|
||||||
|
直接导出core模块的变量,避免兼容层重定向。
|
||||||
|
这些变量被Flag.go和其他模块直接使用。
|
||||||
|
*/
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 版本信息
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
var version = "2.0.2"
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 核心扫描配置 - 直接使用core包变量
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
var (
|
||||||
|
ScanMode string // 扫描模式
|
||||||
|
ThreadNum int // 线程数
|
||||||
|
Timeout int64 // 超时时间
|
||||||
|
DisablePing bool // 禁用ping
|
||||||
|
LocalMode bool // 本地模式
|
||||||
|
)
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 基础认证配置 - 直接定义
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
var (
|
||||||
|
Username string // 用户名
|
||||||
|
Password string // 密码
|
||||||
|
Userdict map[string][]string // 用户字典
|
||||||
|
Passwords []string // 密码列表
|
||||||
|
)
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 网络配置 - 直接定义
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
var (
|
||||||
|
HttpProxy string // HTTP代理
|
||||||
|
Socks5Proxy string // SOCKS5代理
|
||||||
|
)
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 显示控制 - 直接定义
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
var (
|
||||||
|
NoColor bool // 禁用颜色
|
||||||
|
Language string // 语言
|
||||||
|
LogLevel string // 日志级别
|
||||||
|
)
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 端口映射 - 直接定义
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
var (
|
||||||
|
PortMap map[int][]string // 端口映射
|
||||||
|
DefaultMap []string // 默认映射
|
||||||
|
)
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 其他全局变量 - 直接定义,避免多层引用
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
var (
|
||||||
|
// 输出配置
|
||||||
|
Outputfile string
|
||||||
|
OutputFormat string
|
||||||
|
ProgressBar *progressbar.ProgressBar
|
||||||
|
OutputMutex sync.Mutex
|
||||||
|
|
||||||
|
// 日志状态
|
||||||
|
status = logging.NewScanStatus()
|
||||||
|
Num, End int64
|
||||||
|
StartTime = time.Now()
|
||||||
|
|
||||||
|
// 其他变量按需添加
|
||||||
|
)
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 日志级别常量
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
const (
|
||||||
|
LogLevelAll = string(logging.LevelAll)
|
||||||
|
LogLevelError = string(logging.LevelError)
|
||||||
|
LogLevelBase = string(logging.LevelBase)
|
||||||
|
LogLevelInfo = string(logging.LevelInfo)
|
||||||
|
LogLevelSuccess = string(logging.LevelSuccess)
|
||||||
|
LogLevelDebug = string(logging.LevelDebug)
|
||||||
|
LogLevelInfoSuccess = string(logging.LevelInfoSuccess)
|
||||||
|
LogLevelBaseInfoSuccess = string(logging.LevelBaseInfoSuccess)
|
||||||
|
)
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 初始化和同步函数
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// 初始化核心配置
|
||||||
|
core.InitGlobalConfig()
|
||||||
|
|
||||||
|
// 同步变量
|
||||||
|
syncWithCore()
|
||||||
|
}
|
||||||
|
|
||||||
|
// syncWithCore 同步common包变量与core包变量
|
||||||
|
func syncWithCore() {
|
||||||
|
// 读取core包的默认值
|
||||||
|
ScanMode = core.ScanMode
|
||||||
|
ThreadNum = core.ThreadNum
|
||||||
|
Timeout = core.Timeout
|
||||||
|
DisablePing = core.DisablePing
|
||||||
|
LocalMode = core.LocalMode
|
||||||
|
|
||||||
|
Username = core.Username
|
||||||
|
Password = core.Password
|
||||||
|
Userdict = core.Userdict
|
||||||
|
Passwords = core.Passwords
|
||||||
|
|
||||||
|
HttpProxy = core.HttpProxy
|
||||||
|
Socks5Proxy = core.Socks5Proxy
|
||||||
|
|
||||||
|
NoColor = core.NoColor
|
||||||
|
Language = core.Language
|
||||||
|
LogLevel = core.LogLevel
|
||||||
|
|
||||||
|
PortMap = core.PortMap
|
||||||
|
DefaultMap = core.DefaultMap
|
||||||
|
}
|
||||||
|
|
||||||
|
// syncToCore 将common包变量同步回core包
|
||||||
|
func syncToCore() {
|
||||||
|
core.ScanMode = ScanMode
|
||||||
|
core.ThreadNum = ThreadNum
|
||||||
|
core.Timeout = Timeout
|
||||||
|
core.DisablePing = DisablePing
|
||||||
|
core.LocalMode = LocalMode
|
||||||
|
|
||||||
|
core.Username = Username
|
||||||
|
core.Password = Password
|
||||||
|
core.Userdict = Userdict
|
||||||
|
core.Passwords = Passwords
|
||||||
|
|
||||||
|
core.HttpProxy = HttpProxy
|
||||||
|
core.Socks5Proxy = Socks5Proxy
|
||||||
|
|
||||||
|
core.NoColor = NoColor
|
||||||
|
core.Language = Language
|
||||||
|
core.LogLevel = LogLevel
|
||||||
|
|
||||||
|
core.PortMap = PortMap
|
||||||
|
core.DefaultMap = DefaultMap
|
||||||
|
}
|
@ -79,6 +79,18 @@ func (l *Logger) SetOutputMutex(mutex *sync.Mutex) {
|
|||||||
l.outputMutex = mutex
|
l.outputMutex = mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetCoordinatedOutput 设置协调输出函数(用于进度条协调)
|
||||||
|
func (l *Logger) SetCoordinatedOutput(fn func(string)) {
|
||||||
|
l.mu.RLock()
|
||||||
|
defer l.mu.RUnlock()
|
||||||
|
|
||||||
|
for _, handler := range l.handlers {
|
||||||
|
if consoleHandler, ok := handler.(*ConsoleHandler); ok {
|
||||||
|
consoleHandler.SetCoordinatedOutput(fn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Log 记录日志
|
// Log 记录日志
|
||||||
func (l *Logger) Log(level LogLevel, content string, metadata ...map[string]interface{}) {
|
func (l *Logger) Log(level LogLevel, content string, metadata ...map[string]interface{}) {
|
||||||
if !l.shouldLog(level) {
|
if !l.shouldLog(level) {
|
||||||
@ -213,10 +225,11 @@ func (l *Logger) Initialize() {
|
|||||||
|
|
||||||
// ConsoleHandler 控制台日志处理器
|
// ConsoleHandler 控制台日志处理器
|
||||||
type ConsoleHandler struct {
|
type ConsoleHandler struct {
|
||||||
config *LoggerConfig
|
config *LoggerConfig
|
||||||
formatter LogFormatter
|
formatter LogFormatter
|
||||||
enabled bool
|
enabled bool
|
||||||
mu sync.RWMutex
|
coordinatedOutput func(string) // 协调输出函数
|
||||||
|
mu sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewConsoleHandler 创建控制台处理器
|
// NewConsoleHandler 创建控制台处理器
|
||||||
@ -243,15 +256,29 @@ func (h *ConsoleHandler) Handle(entry *LogEntry) {
|
|||||||
// 使用自己的格式化器格式化消息
|
// 使用自己的格式化器格式化消息
|
||||||
logMsg := h.formatter.Format(entry)
|
logMsg := h.formatter.Format(entry)
|
||||||
|
|
||||||
// 根据颜色设置输出
|
// 使用协调输出函数,如果设置了的话
|
||||||
if h.config.EnableColor {
|
if h.coordinatedOutput != nil {
|
||||||
if colorAttr, ok := h.config.LevelColors[entry.Level]; ok {
|
if h.config.EnableColor {
|
||||||
color.New(colorAttr).Println(logMsg)
|
if colorAttr, ok := h.config.LevelColors[entry.Level]; ok {
|
||||||
|
coloredMsg := color.New(colorAttr).Sprint(logMsg)
|
||||||
|
h.coordinatedOutput(coloredMsg)
|
||||||
|
} else {
|
||||||
|
h.coordinatedOutput(logMsg)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
h.coordinatedOutput(logMsg)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 回到原来的直接输出方式
|
||||||
|
if h.config.EnableColor {
|
||||||
|
if colorAttr, ok := h.config.LevelColors[entry.Level]; ok {
|
||||||
|
color.New(colorAttr).Println(logMsg)
|
||||||
|
} else {
|
||||||
|
fmt.Println(logMsg)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Println(logMsg)
|
fmt.Println(logMsg)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
fmt.Println(logMsg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据慢速输出设置决定是否添加延迟
|
// 根据慢速输出设置决定是否添加延迟
|
||||||
@ -267,6 +294,13 @@ func (h *ConsoleHandler) SetEnabled(enabled bool) {
|
|||||||
h.enabled = enabled
|
h.enabled = enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetCoordinatedOutput 设置协调输出函数
|
||||||
|
func (h *ConsoleHandler) SetCoordinatedOutput(fn func(string)) {
|
||||||
|
h.mu.Lock()
|
||||||
|
defer h.mu.Unlock()
|
||||||
|
h.coordinatedOutput = fn
|
||||||
|
}
|
||||||
|
|
||||||
// IsEnabled 检查处理器是否启用
|
// IsEnabled 检查处理器是否启用
|
||||||
func (h *ConsoleHandler) IsEnabled() bool {
|
func (h *ConsoleHandler) IsEnabled() bool {
|
||||||
h.mu.RLock()
|
h.mu.RLock()
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
"github.com/shadow1ng/fscan/common/i18n"
|
"github.com/shadow1ng/fscan/common/i18n"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
"golang.org/x/net/icmp"
|
"golang.org/x/net/icmp"
|
||||||
"net"
|
"net"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@ -68,9 +69,9 @@ func handleAliveHosts(chanHosts chan string, hostslist []string, isPing bool) {
|
|||||||
protocol = "PING"
|
protocol = "PING"
|
||||||
}
|
}
|
||||||
|
|
||||||
result := &common.ScanResult{
|
result := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.HOST,
|
Type: output.TypeHost,
|
||||||
Target: ip,
|
Target: ip,
|
||||||
Status: "alive",
|
Status: "alive",
|
||||||
Details: map[string]interface{}{
|
Details: map[string]interface{}{
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
"github.com/shadow1ng/fscan/common/i18n"
|
"github.com/shadow1ng/fscan/common/i18n"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
"github.com/shadow1ng/fscan/common/parsers"
|
"github.com/shadow1ng/fscan/common/parsers"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
"golang.org/x/sync/semaphore"
|
"golang.org/x/sync/semaphore"
|
||||||
@ -85,8 +86,8 @@ func EnhancedPortScan(hosts []string, ports string, timeout int64) []string {
|
|||||||
atomic.AddInt64(&count, 1)
|
atomic.AddInt64(&count, 1)
|
||||||
aliveMap.Store(addr, struct{}{})
|
aliveMap.Store(addr, struct{}{})
|
||||||
common.LogInfo("端口开放 " + addr)
|
common.LogInfo("端口开放 " + addr)
|
||||||
common.SaveResult(&common.ScanResult{
|
common.SaveResult(&output.ScanResult{
|
||||||
Time: time.Now(), Type: common.PORT, Target: host,
|
Time: time.Now(), Type: output.TypePort, Target: host,
|
||||||
Status: "open", Details: map[string]interface{}{"port": port},
|
Status: "open", Details: map[string]interface{}{"port": port},
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -116,8 +117,8 @@ func EnhancedPortScan(hosts []string, ports string, timeout int64) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 保存服务结果
|
// 保存服务结果
|
||||||
common.SaveResult(&common.ScanResult{
|
common.SaveResult(&output.ScanResult{
|
||||||
Time: time.Now(), Type: common.SERVICE, Target: host,
|
Time: time.Now(), Type: output.TypeService, Target: host,
|
||||||
Status: "identified", Details: details,
|
Status: "identified", Details: details,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ActiveMQCredential 表示一个ActiveMQ凭据
|
// ActiveMQCredential 表示一个ActiveMQ凭据
|
||||||
@ -300,9 +301,9 @@ func saveActiveMQSuccess(info *common.HostInfo, target string, credential Active
|
|||||||
common.LogSuccess(successMsg)
|
common.LogSuccess(successMsg)
|
||||||
|
|
||||||
// 保存结果
|
// 保存结果
|
||||||
result := &common.ScanResult{
|
result := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: map[string]interface{}{
|
Details: map[string]interface{}{
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
|
|
||||||
"github.com/gocql/gocql"
|
"github.com/gocql/gocql"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CassandraProxyDialer 实现gocql.Dialer接口,支持代理连接
|
// CassandraProxyDialer 实现gocql.Dialer接口,支持代理连接
|
||||||
@ -353,9 +354,9 @@ func saveCassandraSuccess(info *common.HostInfo, target string, credential Cassa
|
|||||||
common.LogSuccess(successMsg)
|
common.LogSuccess(successMsg)
|
||||||
|
|
||||||
// 保存结果
|
// 保存结果
|
||||||
result := &common.ScanResult{
|
result := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: details,
|
Details: details,
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
package Plugins
|
package Plugins
|
||||||
|
|
||||||
import "github.com/shadow1ng/fscan/common"
|
import "github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
|
|
||||||
func DCInfoScan(info *common.HostInfo) (err error) {
|
func DCInfoScan(info *common.HostInfo) (err error) {
|
||||||
return nil
|
return nil
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@ -295,9 +296,9 @@ func saveElasticResult(info *common.HostInfo, target string, credential ElasticC
|
|||||||
common.LogSuccess(successMsg)
|
common.LogSuccess(successMsg)
|
||||||
|
|
||||||
// 保存结果
|
// 保存结果
|
||||||
result := &common.ScanResult{
|
result := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: details,
|
Details: details,
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/jlaffaye/ftp"
|
"github.com/jlaffaye/ftp"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -326,9 +327,9 @@ func saveFtpResult(info *common.HostInfo, target string, result *FtpScanResult)
|
|||||||
common.LogSuccess(successMsg)
|
common.LogSuccess(successMsg)
|
||||||
|
|
||||||
// 保存结果
|
// 保存结果
|
||||||
vulnResult := &common.ScanResult{
|
vulnResult := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: details,
|
Details: details,
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
"net"
|
"net"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -192,9 +193,9 @@ func read(text []byte, host string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 保存扫描结果
|
// 保存扫描结果
|
||||||
result := &common.ScanResult{
|
result := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.SERVICE,
|
Type: output.TypeService,
|
||||||
Target: host,
|
Target: host,
|
||||||
Status: "identified",
|
Status: "identified",
|
||||||
Details: details,
|
Details: details,
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IMAPCredential 表示一个IMAP凭据
|
// IMAPCredential 表示一个IMAP凭据
|
||||||
@ -309,9 +310,9 @@ func saveIMAPResult(info *common.HostInfo, target string, credential IMAPCredent
|
|||||||
common.LogSuccess(successMsg)
|
common.LogSuccess(successMsg)
|
||||||
|
|
||||||
// 保存结果
|
// 保存结果
|
||||||
vulnResult := &common.ScanResult{
|
vulnResult := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: map[string]interface{}{
|
Details: map[string]interface{}{
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/IBM/sarama"
|
"github.com/IBM/sarama"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -45,9 +46,9 @@ func KafkaScan(info *common.HostInfo) error {
|
|||||||
common.LogSuccess(fmt.Sprintf("Kafka服务 %s 无需认证即可访问", target))
|
common.LogSuccess(fmt.Sprintf("Kafka服务 %s 无需认证即可访问", target))
|
||||||
|
|
||||||
// 保存无认证访问结果
|
// 保存无认证访问结果
|
||||||
result := &common.ScanResult{
|
result := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: map[string]interface{}{
|
Details: map[string]interface{}{
|
||||||
@ -79,9 +80,9 @@ func KafkaScan(info *common.HostInfo) error {
|
|||||||
result := concurrentKafkaScan(ctx, info, credentials, common.Timeout, common.MaxRetries)
|
result := concurrentKafkaScan(ctx, info, credentials, common.Timeout, common.MaxRetries)
|
||||||
if result != nil {
|
if result != nil {
|
||||||
// 保存爆破成功结果
|
// 保存爆破成功结果
|
||||||
vulnResult := &common.ScanResult{
|
vulnResult := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: map[string]interface{}{
|
Details: map[string]interface{}{
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/go-ldap/ldap/v3"
|
"github.com/go-ldap/ldap/v3"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LDAPCredential 表示一个LDAP凭据
|
// LDAPCredential 表示一个LDAP凭据
|
||||||
@ -296,9 +297,9 @@ func saveLDAPResult(info *common.HostInfo, target string, result *LDAPScanResult
|
|||||||
common.LogSuccess(successMsg)
|
common.LogSuccess(successMsg)
|
||||||
|
|
||||||
// 保存结果
|
// 保存结果
|
||||||
vulnResult := &common.ScanResult{
|
vulnResult := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: details,
|
Details: details,
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -218,9 +219,9 @@ func MS17010Scan(info *common.HostInfo) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 保存 MS17-010 漏洞结果
|
// 保存 MS17-010 漏洞结果
|
||||||
result := &common.ScanResult{
|
result := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: ip,
|
Target: ip,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: details,
|
Details: details,
|
||||||
@ -248,9 +249,9 @@ func MS17010Scan(info *common.HostInfo) error {
|
|||||||
common.LogSuccess(fmt.Sprintf("发现后门 %s DOUBLEPULSAR", ip))
|
common.LogSuccess(fmt.Sprintf("发现后门 %s DOUBLEPULSAR", ip))
|
||||||
|
|
||||||
// 保存 DOUBLEPULSAR 后门结果
|
// 保存 DOUBLEPULSAR 后门结果
|
||||||
backdoorResult := &common.ScanResult{
|
backdoorResult := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: ip,
|
Target: ip,
|
||||||
Status: "backdoor",
|
Status: "backdoor",
|
||||||
Details: map[string]interface{}{
|
Details: map[string]interface{}{
|
||||||
@ -270,9 +271,9 @@ func MS17010Scan(info *common.HostInfo) error {
|
|||||||
common.LogBase(fmt.Sprintf("系统信息 %s [%s]", ip, os))
|
common.LogBase(fmt.Sprintf("系统信息 %s [%s]", ip, os))
|
||||||
|
|
||||||
// 保存系统信息
|
// 保存系统信息
|
||||||
sysResult := &common.ScanResult{
|
sysResult := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.SERVICE,
|
Type: output.TypeService,
|
||||||
Target: ip,
|
Target: ip,
|
||||||
Status: "identified",
|
Status: "identified",
|
||||||
Details: map[string]interface{}{
|
Details: map[string]interface{}{
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
|
|
||||||
mssql "github.com/denisenkom/go-mssqldb"
|
mssql "github.com/denisenkom/go-mssqldb"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MSSQLProxyDialer 自定义dialer结构体
|
// MSSQLProxyDialer 自定义dialer结构体
|
||||||
@ -315,9 +316,9 @@ func saveMssqlResult(info *common.HostInfo, target string, credential MssqlCrede
|
|||||||
common.LogSuccess(successMsg)
|
common.LogSuccess(successMsg)
|
||||||
|
|
||||||
// 保存结果
|
// 保存结果
|
||||||
vulnResult := &common.ScanResult{
|
vulnResult := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: map[string]interface{}{
|
Details: map[string]interface{}{
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -29,9 +30,9 @@ func MemcachedScan(info *common.HostInfo) error {
|
|||||||
|
|
||||||
if result.Success {
|
if result.Success {
|
||||||
// 保存成功结果
|
// 保存成功结果
|
||||||
scanResult := &common.ScanResult{
|
scanResult := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: map[string]interface{}{
|
Details: map[string]interface{}{
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
package Plugins
|
package Plugins
|
||||||
|
|
||||||
import "github.com/shadow1ng/fscan/common"
|
import "github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
|
|
||||||
func MiniDump(info *common.HostInfo) (err error) {
|
func MiniDump(info *common.HostInfo) (err error) {
|
||||||
return nil
|
return nil
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ModbusScanResult 表示 Modbus 扫描结果
|
// ModbusScanResult 表示 Modbus 扫描结果
|
||||||
@ -251,9 +252,9 @@ func parseModbusResponse(response []byte) string {
|
|||||||
// saveModbusResult 保存Modbus扫描结果
|
// saveModbusResult 保存Modbus扫描结果
|
||||||
func saveModbusResult(info *common.HostInfo, target string, result *ModbusScanResult) {
|
func saveModbusResult(info *common.HostInfo, target string, result *ModbusScanResult) {
|
||||||
// 保存扫描结果
|
// 保存扫描结果
|
||||||
scanResult := &common.ScanResult{
|
scanResult := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: map[string]interface{}{
|
Details: map[string]interface{}{
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MongodbScan 执行MongoDB未授权扫描
|
// MongodbScan 执行MongoDB未授权扫描
|
||||||
@ -53,9 +54,9 @@ func MongodbScan(info *common.HostInfo) error {
|
|||||||
common.LogSuccess(fmt.Sprintf("MongoDB %v 未授权访问", target))
|
common.LogSuccess(fmt.Sprintf("MongoDB %v 未授权访问", target))
|
||||||
|
|
||||||
// 保存未授权访问结果
|
// 保存未授权访问结果
|
||||||
scanResult := &common.ScanResult{
|
scanResult := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: map[string]interface{}{
|
Details: map[string]interface{}{
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
|
|
||||||
"github.com/go-sql-driver/mysql"
|
"github.com/go-sql-driver/mysql"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MySQLProxyDialer 自定义dialer结构体
|
// MySQLProxyDialer 自定义dialer结构体
|
||||||
@ -327,9 +328,9 @@ func saveMySQLResult(info *common.HostInfo, target string, credential MySQLCrede
|
|||||||
common.LogSuccess(successMsg)
|
common.LogSuccess(successMsg)
|
||||||
|
|
||||||
// 保存结果
|
// 保存结果
|
||||||
vulnResult := &common.ScanResult{
|
vulnResult := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: map[string]interface{}{
|
Details: map[string]interface{}{
|
||||||
|
@ -9,6 +9,7 @@ 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"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Neo4jCredential 表示一个Neo4j凭据
|
// Neo4jCredential 表示一个Neo4j凭据
|
||||||
@ -349,9 +350,9 @@ func saveNeo4jResult(info *common.HostInfo, target string, result *Neo4jScanResu
|
|||||||
common.LogSuccess(successMsg)
|
common.LogSuccess(successMsg)
|
||||||
|
|
||||||
// 保存结果
|
// 保存结果
|
||||||
vulnResult := &common.ScanResult{
|
vulnResult := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: details,
|
Details: details,
|
||||||
|
@ -52,15 +52,7 @@ func NetBIOS(info *common.HostInfo) error {
|
|||||||
details["os_version"] = netbios.OsVersion
|
details["os_version"] = netbios.OsVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
scanResult := &common.ScanResult{
|
// NetBIOS信息已通过上面的LogSuccess记录,不需要额外保存结果
|
||||||
Time: time.Now(),
|
|
||||||
Type: common.SERVICE,
|
|
||||||
Target: info.Host,
|
|
||||||
Status: "identified",
|
|
||||||
Details: details,
|
|
||||||
}
|
|
||||||
|
|
||||||
common.SaveResult(scanResult)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return errNetBIOS
|
return errNetBIOS
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
_ "github.com/sijms/go-ora/v2"
|
_ "github.com/sijms/go-ora/v2"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@ -417,9 +418,9 @@ func saveOracleResult(info *common.HostInfo, target string, credential OracleCre
|
|||||||
common.LogSuccess(successMsg)
|
common.LogSuccess(successMsg)
|
||||||
|
|
||||||
// 保存结果
|
// 保存结果
|
||||||
vulnResult := &common.ScanResult{
|
vulnResult := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: map[string]interface{}{
|
Details: map[string]interface{}{
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
)
|
)
|
||||||
|
|
||||||
// POP3Credential 表示一个POP3凭据
|
// POP3Credential 表示一个POP3凭据
|
||||||
@ -395,9 +396,9 @@ func savePOP3Result(info *common.HostInfo, target string, result *POP3ScanResult
|
|||||||
common.LogSuccess(successMsg)
|
common.LogSuccess(successMsg)
|
||||||
|
|
||||||
// 保存结果
|
// 保存结果
|
||||||
vulnResult := &common.ScanResult{
|
vulnResult := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: map[string]interface{}{
|
Details: map[string]interface{}{
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
|
|
||||||
"github.com/lib/pq"
|
"github.com/lib/pq"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PostgresProxyDialer 自定义dialer结构体
|
// PostgresProxyDialer 自定义dialer结构体
|
||||||
@ -302,9 +303,9 @@ func savePostgresResult(info *common.HostInfo, target string, credential Postgre
|
|||||||
common.LogSuccess(successMsg)
|
common.LogSuccess(successMsg)
|
||||||
|
|
||||||
// 保存结果
|
// 保存结果
|
||||||
vulnResult := &common.ScanResult{
|
vulnResult := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: map[string]interface{}{
|
Details: map[string]interface{}{
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
"github.com/tomatome/grdp/core"
|
"github.com/tomatome/grdp/core"
|
||||||
"github.com/tomatome/grdp/glog"
|
"github.com/tomatome/grdp/glog"
|
||||||
"github.com/tomatome/grdp/protocol/nla"
|
"github.com/tomatome/grdp/protocol/nla"
|
||||||
@ -255,9 +256,9 @@ func saveRdpResult(info *common.HostInfo, target string, port int, credential RD
|
|||||||
details["domain"] = credential.Domain
|
details["domain"] = credential.Domain
|
||||||
}
|
}
|
||||||
|
|
||||||
vulnResult := &common.ScanResult{
|
vulnResult := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: details,
|
Details: details,
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
amqp "github.com/rabbitmq/amqp091-go"
|
amqp "github.com/rabbitmq/amqp091-go"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@ -291,9 +292,9 @@ func saveRabbitMQResult(info *common.HostInfo, target string, credential RabbitM
|
|||||||
common.LogSuccess(successMsg)
|
common.LogSuccess(successMsg)
|
||||||
|
|
||||||
// 保存结果
|
// 保存结果
|
||||||
vulnResult := &common.ScanResult{
|
vulnResult := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: map[string]interface{}{
|
Details: map[string]interface{}{
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
@ -62,9 +63,9 @@ func RedisScan(info *common.HostInfo) error {
|
|||||||
common.LogSuccess(fmt.Sprintf("Redis无密码连接成功: %s", target))
|
common.LogSuccess(fmt.Sprintf("Redis无密码连接成功: %s", target))
|
||||||
|
|
||||||
// 保存未授权访问结果
|
// 保存未授权访问结果
|
||||||
scanResult := &common.ScanResult{
|
scanResult := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: map[string]interface{}{
|
Details: map[string]interface{}{
|
||||||
@ -107,9 +108,9 @@ func RedisScan(info *common.HostInfo) error {
|
|||||||
common.LogSuccess(fmt.Sprintf("Redis认证成功 %s [%s]", target, result.Credential.Password))
|
common.LogSuccess(fmt.Sprintf("Redis认证成功 %s [%s]", target, result.Credential.Password))
|
||||||
|
|
||||||
// 保存弱密码结果
|
// 保存弱密码结果
|
||||||
scanResult := &common.ScanResult{
|
scanResult := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: map[string]interface{}{
|
Details: map[string]interface{}{
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RsyncCredential 表示一个Rsync凭据
|
// RsyncCredential 表示一个Rsync凭据
|
||||||
@ -465,9 +466,9 @@ func saveRsyncResult(info *common.HostInfo, target string, result *RsyncScanResu
|
|||||||
common.LogSuccess(successMsg)
|
common.LogSuccess(successMsg)
|
||||||
|
|
||||||
// 保存结果
|
// 保存结果
|
||||||
vulnResult := &common.ScanResult{
|
vulnResult := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: details,
|
Details: details,
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
"github.com/stacktitan/smb/smb"
|
"github.com/stacktitan/smb/smb"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@ -242,9 +243,9 @@ func saveSmbResult(info *common.HostInfo, target string, credential SmbCredentia
|
|||||||
common.LogSuccess(successMsg)
|
common.LogSuccess(successMsg)
|
||||||
|
|
||||||
// 保存结果
|
// 保存结果
|
||||||
result := &common.ScanResult{
|
result := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: details,
|
Details: details,
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
|
|
||||||
"github.com/hirochachacha/go-smb2"
|
"github.com/hirochachacha/go-smb2"
|
||||||
)
|
)
|
||||||
@ -401,9 +402,9 @@ func logSuccessfulAuth(info *common.HostInfo, user, pass string, hash []byte) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 保存认证成功结果
|
// 保存认证成功结果
|
||||||
result := &common.ScanResult{
|
result := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "success",
|
Status: "success",
|
||||||
Details: map[string]interface{}{
|
Details: map[string]interface{}{
|
||||||
@ -456,9 +457,9 @@ func logShareInfo(info *common.HostInfo, user string, pass string, hash []byte,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 保存共享信息结果
|
// 保存共享信息结果
|
||||||
result := &common.ScanResult{
|
result := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "shares-found",
|
Status: "shares-found",
|
||||||
Details: map[string]interface{}{
|
Details: map[string]interface{}{
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SmtpCredential 表示一个SMTP凭据
|
// SmtpCredential 表示一个SMTP凭据
|
||||||
@ -314,9 +315,9 @@ func saveSmtpResult(info *common.HostInfo, target string, result *SmtpScanResult
|
|||||||
common.LogSuccess(successMsg)
|
common.LogSuccess(successMsg)
|
||||||
|
|
||||||
// 保存结果
|
// 保存结果
|
||||||
vulnResult := &common.ScanResult{
|
vulnResult := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: details,
|
Details: details,
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gosnmp/gosnmp"
|
"github.com/gosnmp/gosnmp"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -66,9 +67,9 @@ func SNMPScan(info *common.HostInfo) (tmperr error) {
|
|||||||
common.LogSuccess(successMsg)
|
common.LogSuccess(successMsg)
|
||||||
|
|
||||||
// 保存结果
|
// 保存结果
|
||||||
vulnResult := &common.ScanResult{
|
vulnResult := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: map[string]interface{}{
|
Details: map[string]interface{}{
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
@ -348,9 +349,9 @@ func logAndSaveSuccess(info *common.HostInfo, target string, result *SshScanResu
|
|||||||
|
|
||||||
common.LogSuccess(successMsg)
|
common.LogSuccess(successMsg)
|
||||||
|
|
||||||
vulnResult := &common.ScanResult{
|
vulnResult := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: details,
|
Details: details,
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TelnetCredential 表示一个Telnet凭据
|
// TelnetCredential 表示一个Telnet凭据
|
||||||
@ -313,9 +314,9 @@ func saveTelnetResult(info *common.HostInfo, target string, result *TelnetScanRe
|
|||||||
common.LogSuccess(successMsg)
|
common.LogSuccess(successMsg)
|
||||||
|
|
||||||
// 保存结果
|
// 保存结果
|
||||||
vulnResult := &common.ScanResult{
|
vulnResult := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: details,
|
Details: details,
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/mitchellh/go-vnc"
|
"github.com/mitchellh/go-vnc"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
)
|
)
|
||||||
|
|
||||||
// VncCredential 表示VNC凭据
|
// VncCredential 表示VNC凭据
|
||||||
@ -257,9 +258,9 @@ func saveVncResult(info *common.HostInfo, target string, credential VncCredentia
|
|||||||
common.LogSuccess(successLog)
|
common.LogSuccess(successLog)
|
||||||
|
|
||||||
// 保存结果
|
// 保存结果
|
||||||
vulnResult := &common.ScanResult{
|
vulnResult := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: map[string]interface{}{
|
Details: map[string]interface{}{
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
"github.com/shadow1ng/fscan/webscan"
|
"github.com/shadow1ng/fscan/webscan"
|
||||||
"github.com/shadow1ng/fscan/webscan/lib"
|
"github.com/shadow1ng/fscan/webscan/lib"
|
||||||
"golang.org/x/text/encoding/simplifiedchinese"
|
"golang.org/x/text/encoding/simplifiedchinese"
|
||||||
@ -379,9 +380,9 @@ func saveWebResult(info *common.HostInfo, resp *WebResponse) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 保存扫描结果
|
// 保存扫描结果
|
||||||
result := &common.ScanResult{
|
result := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.SERVICE,
|
Type: output.TypeService,
|
||||||
Target: info.Host,
|
Target: info.Host,
|
||||||
Status: "identified",
|
Status: "identified",
|
||||||
Details: map[string]interface{}{
|
Details: map[string]interface{}{
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/config"
|
||||||
"github.com/shadow1ng/fscan/webscan/lib"
|
"github.com/shadow1ng/fscan/webscan/lib"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -72,13 +73,13 @@ func WebScan(info *common.HostInfo) {
|
|||||||
// 根据扫描策略执行POC
|
// 根据扫描策略执行POC
|
||||||
if common.Pocinfo.PocName == "" && len(info.Infostr) == 0 {
|
if common.Pocinfo.PocName == "" && len(info.Infostr) == 0 {
|
||||||
// 执行所有POC
|
// 执行所有POC
|
||||||
executePOCs(ctx, common.PocInfo{Target: target})
|
executePOCs(ctx, config.PocInfo{Target: target})
|
||||||
} else if len(info.Infostr) > 0 {
|
} else if len(info.Infostr) > 0 {
|
||||||
// 基于指纹信息执行POC
|
// 基于指纹信息执行POC
|
||||||
scanByFingerprints(ctx, target, info.Infostr)
|
scanByFingerprints(ctx, target, info.Infostr)
|
||||||
} else if common.Pocinfo.PocName != "" {
|
} else if common.Pocinfo.PocName != "" {
|
||||||
// 基于指定POC名称执行
|
// 基于指定POC名称执行
|
||||||
executePOCs(ctx, common.PocInfo{Target: target, PocName: common.Pocinfo.PocName})
|
executePOCs(ctx, config.PocInfo{Target: target, PocName: common.Pocinfo.PocName})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,12 +118,12 @@ func scanByFingerprints(ctx context.Context, target string, fingerprints []strin
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
executePOCs(ctx, common.PocInfo{Target: target, PocName: pocName})
|
executePOCs(ctx, config.PocInfo{Target: target, PocName: pocName})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// executePOCs 执行POC检测
|
// executePOCs 执行POC检测
|
||||||
func executePOCs(ctx context.Context, pocInfo common.PocInfo) {
|
func executePOCs(ctx context.Context, pocInfo config.PocInfo) {
|
||||||
// 验证目标
|
// 验证目标
|
||||||
if pocInfo.Target == "" {
|
if pocInfo.Target == "" {
|
||||||
common.LogError(ErrEmptyTarget.Error())
|
common.LogError(ErrEmptyTarget.Error())
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/google/cel-go/cel"
|
"github.com/google/cel-go/cel"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
"github.com/shadow1ng/fscan/webscan/info"
|
"github.com/shadow1ng/fscan/webscan/info"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -90,9 +91,9 @@ func CheckMultiPoc(req *http.Request, pocs []*Poc, workers int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 创建并保存扫描结果
|
// 创建并保存扫描结果
|
||||||
result := &common.ScanResult{
|
result := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: task.Req.URL.String(),
|
Target: task.Req.URL.String(),
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: details,
|
Details: details,
|
||||||
@ -495,9 +496,9 @@ func clusterpoc(oReq *http.Request, p *Poc, variableMap map[string]interface{},
|
|||||||
|
|
||||||
// 保存漏洞结果(除非明确指示跳过)
|
// 保存漏洞结果(除非明确指示跳过)
|
||||||
if !skipSave {
|
if !skipSave {
|
||||||
result := &common.ScanResult{
|
result := &output.ScanResult{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: common.VULN,
|
Type: output.TypeVuln,
|
||||||
Target: targetURL,
|
Target: targetURL,
|
||||||
Status: "vulnerable",
|
Status: "vulnerable",
|
||||||
Details: details,
|
Details: details,
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
"golang.org/x/net/proxy"
|
"github.com/shadow1ng/fscan/common/proxy"
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -67,15 +67,17 @@ func InitHttpClient(ThreadsNum int, DownProxy string, Timeout time.Duration) err
|
|||||||
|
|
||||||
// 配置Socks5代理
|
// 配置Socks5代理
|
||||||
if common.Socks5Proxy != "" {
|
if common.Socks5Proxy != "" {
|
||||||
dialSocksProxy, err := common.Socks5Dialer(dialer)
|
proxyConfig := &proxy.ProxyConfig{
|
||||||
|
Type: proxy.ProxyTypeSOCKS5,
|
||||||
|
Address: common.Socks5Proxy,
|
||||||
|
Timeout: time.Second * 10,
|
||||||
|
}
|
||||||
|
proxyManager := proxy.NewProxyManager(proxyConfig)
|
||||||
|
proxyDialer, err := proxyManager.GetDialer()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if contextDialer, ok := dialSocksProxy.(proxy.ContextDialer); ok {
|
tr.DialContext = proxyDialer.DialContext
|
||||||
tr.DialContext = contextDialer.DialContext
|
|
||||||
} else {
|
|
||||||
return errors.New("无法转换为DialContext类型")
|
|
||||||
}
|
|
||||||
} else if DownProxy != "" {
|
} else if DownProxy != "" {
|
||||||
// 处理其他代理配置
|
// 处理其他代理配置
|
||||||
if DownProxy == "1" {
|
if DownProxy == "1" {
|
||||||
|
Loading…
Reference in New Issue
Block a user