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 // 本地模式
|
||||
|
||||
// 基础认证配置
|
||||
Username string // 用户名
|
||||
Password string // 密码
|
||||
Userdict map[string][]string // 用户字典
|
||||
Passwords []string // 密码列表
|
||||
Username string // 用户名
|
||||
Password string // 密码
|
||||
Userdict map[string][]string // 用户字典
|
||||
Passwords []string // 密码列表
|
||||
|
||||
// 网络配置
|
||||
HttpProxy string // HTTP代理
|
||||
|
@ -131,6 +131,9 @@ func Parse(Info *HostInfo) error {
|
||||
// 显示解析结果摘要
|
||||
showParseSummary(result.Config)
|
||||
|
||||
// 同步变量到core包
|
||||
syncToCore()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -499,6 +502,9 @@ func applyLogLevel() {
|
||||
}
|
||||
newLogger.SetOutputMutex(&OutputMutex)
|
||||
|
||||
// 设置协调输出函数,使用LogWithProgress
|
||||
newLogger.SetCoordinatedOutput(LogWithProgress)
|
||||
|
||||
// 更新全局日志管理器
|
||||
globalLogger = newLogger
|
||||
status = newLogger.GetScanStatus()
|
||||
|
@ -72,6 +72,9 @@ func (pm *ProgressManager) InitProgress(total int64, description string) {
|
||||
pm.isActive = true
|
||||
pm.enabled = true
|
||||
|
||||
// 为进度条保留空间
|
||||
pm.setupProgressSpace()
|
||||
|
||||
// 初始显示进度条
|
||||
pm.renderProgress()
|
||||
}
|
||||
@ -130,24 +133,23 @@ func (pm *ProgressManager) FinishProgress() {
|
||||
pm.isActive = false
|
||||
}
|
||||
|
||||
// reserveProgressSpace 为进度条保留底部空间
|
||||
func (pm *ProgressManager) reserveProgressSpace() {
|
||||
if pm.terminalHeight <= 0 {
|
||||
return
|
||||
}
|
||||
// setupProgressSpace 设置进度条空间
|
||||
func (pm *ProgressManager) setupProgressSpace() {
|
||||
// 简化设计:进度条在原地更新,不需要预留额外空间
|
||||
// 只是标记进度条开始的位置
|
||||
pm.lastContentLine = 0
|
||||
}
|
||||
|
||||
// 移动到底部保留区域上方
|
||||
targetLine := pm.terminalHeight - pm.reservedLines
|
||||
fmt.Printf("\033[%d;1H", targetLine)
|
||||
// moveToContentArea 移动到内容输出区域
|
||||
func (pm *ProgressManager) moveToContentArea() {
|
||||
// 对于简化的实现,直接在当前位置输出内容
|
||||
// 不需要复杂的光标移动
|
||||
}
|
||||
|
||||
// 在底部创建空行
|
||||
for i := 0; i < pm.reservedLines; i++ {
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// 回到内容输出位置
|
||||
fmt.Printf("\033[%d;1H", targetLine)
|
||||
pm.lastContentLine = targetLine - 1
|
||||
// moveToProgressLine 移动到进度条位置
|
||||
func (pm *ProgressManager) moveToProgressLine() {
|
||||
// 移动到行首准备重绘进度条
|
||||
fmt.Print("\r")
|
||||
}
|
||||
|
||||
// renderProgress 渲染进度条(使用锁避免输出冲突)
|
||||
@ -155,9 +157,6 @@ func (pm *ProgressManager) renderProgress() {
|
||||
pm.outputMutex.Lock()
|
||||
defer pm.outputMutex.Unlock()
|
||||
|
||||
// 清除当前行并回到行首
|
||||
fmt.Print("\033[2K\r")
|
||||
|
||||
pm.renderProgressUnsafe()
|
||||
}
|
||||
|
||||
@ -308,13 +307,13 @@ func LogWithProgress(message string) {
|
||||
pm.outputMutex.Lock()
|
||||
defer pm.outputMutex.Unlock()
|
||||
|
||||
// 清除当前进度条
|
||||
// 清除当前行(清除进度条)
|
||||
fmt.Print("\033[2K\r")
|
||||
|
||||
// 输出消息
|
||||
// 输出日志消息
|
||||
fmt.Println(message)
|
||||
|
||||
// 重新绘制进度条
|
||||
// 重绘进度条
|
||||
pm.renderProgressUnsafe()
|
||||
}
|
||||
|
||||
@ -324,6 +323,9 @@ func (pm *ProgressManager) renderProgressUnsafe() {
|
||||
return
|
||||
}
|
||||
|
||||
// 移动到行首并清除当前行
|
||||
fmt.Print("\033[2K\r")
|
||||
|
||||
// 生成进度条内容
|
||||
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
|
||||
}
|
||||
|
||||
// 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 记录日志
|
||||
func (l *Logger) Log(level LogLevel, content string, metadata ...map[string]interface{}) {
|
||||
if !l.shouldLog(level) {
|
||||
@ -213,10 +225,11 @@ func (l *Logger) Initialize() {
|
||||
|
||||
// ConsoleHandler 控制台日志处理器
|
||||
type ConsoleHandler struct {
|
||||
config *LoggerConfig
|
||||
formatter LogFormatter
|
||||
enabled bool
|
||||
mu sync.RWMutex
|
||||
config *LoggerConfig
|
||||
formatter LogFormatter
|
||||
enabled bool
|
||||
coordinatedOutput func(string) // 协调输出函数
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// NewConsoleHandler 创建控制台处理器
|
||||
@ -243,15 +256,29 @@ func (h *ConsoleHandler) Handle(entry *LogEntry) {
|
||||
// 使用自己的格式化器格式化消息
|
||||
logMsg := h.formatter.Format(entry)
|
||||
|
||||
// 根据颜色设置输出
|
||||
if h.config.EnableColor {
|
||||
if colorAttr, ok := h.config.LevelColors[entry.Level]; ok {
|
||||
color.New(colorAttr).Println(logMsg)
|
||||
// 使用协调输出函数,如果设置了的话
|
||||
if h.coordinatedOutput != nil {
|
||||
if h.config.EnableColor {
|
||||
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 {
|
||||
fmt.Println(logMsg)
|
||||
}
|
||||
} else {
|
||||
fmt.Println(logMsg)
|
||||
}
|
||||
|
||||
// 根据慢速输出设置决定是否添加延迟
|
||||
@ -267,6 +294,13 @@ func (h *ConsoleHandler) SetEnabled(enabled bool) {
|
||||
h.enabled = enabled
|
||||
}
|
||||
|
||||
// SetCoordinatedOutput 设置协调输出函数
|
||||
func (h *ConsoleHandler) SetCoordinatedOutput(fn func(string)) {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
h.coordinatedOutput = fn
|
||||
}
|
||||
|
||||
// IsEnabled 检查处理器是否启用
|
||||
func (h *ConsoleHandler) IsEnabled() bool {
|
||||
h.mu.RLock()
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/i18n"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
"golang.org/x/net/icmp"
|
||||
"net"
|
||||
"os/exec"
|
||||
@ -68,9 +69,9 @@ func handleAliveHosts(chanHosts chan string, hostslist []string, isPing bool) {
|
||||
protocol = "PING"
|
||||
}
|
||||
|
||||
result := &common.ScanResult{
|
||||
result := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.HOST,
|
||||
Type: output.TypeHost,
|
||||
Target: ip,
|
||||
Status: "alive",
|
||||
Details: map[string]interface{}{
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/i18n"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
"github.com/shadow1ng/fscan/common/parsers"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"golang.org/x/sync/semaphore"
|
||||
@ -85,8 +86,8 @@ func EnhancedPortScan(hosts []string, ports string, timeout int64) []string {
|
||||
atomic.AddInt64(&count, 1)
|
||||
aliveMap.Store(addr, struct{}{})
|
||||
common.LogInfo("端口开放 " + addr)
|
||||
common.SaveResult(&common.ScanResult{
|
||||
Time: time.Now(), Type: common.PORT, Target: host,
|
||||
common.SaveResult(&output.ScanResult{
|
||||
Time: time.Now(), Type: output.TypePort, Target: host,
|
||||
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{
|
||||
Time: time.Now(), Type: common.SERVICE, Target: host,
|
||||
common.SaveResult(&output.ScanResult{
|
||||
Time: time.Now(), Type: output.TypeService, Target: host,
|
||||
Status: "identified", Details: details,
|
||||
})
|
||||
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
)
|
||||
|
||||
// ActiveMQCredential 表示一个ActiveMQ凭据
|
||||
@ -300,9 +301,9 @@ func saveActiveMQSuccess(info *common.HostInfo, target string, credential Active
|
||||
common.LogSuccess(successMsg)
|
||||
|
||||
// 保存结果
|
||||
result := &common.ScanResult{
|
||||
result := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
Details: map[string]interface{}{
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
)
|
||||
|
||||
// CassandraProxyDialer 实现gocql.Dialer接口,支持代理连接
|
||||
@ -353,9 +354,9 @@ func saveCassandraSuccess(info *common.HostInfo, target string, credential Cassa
|
||||
common.LogSuccess(successMsg)
|
||||
|
||||
// 保存结果
|
||||
result := &common.ScanResult{
|
||||
result := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
Details: details,
|
||||
|
@ -3,6 +3,7 @@
|
||||
package Plugins
|
||||
|
||||
import "github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
|
||||
func DCInfoScan(info *common.HostInfo) (err error) {
|
||||
return nil
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -295,9 +296,9 @@ func saveElasticResult(info *common.HostInfo, target string, credential ElasticC
|
||||
common.LogSuccess(successMsg)
|
||||
|
||||
// 保存结果
|
||||
result := &common.ScanResult{
|
||||
result := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
Details: details,
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"github.com/jlaffaye/ftp"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@ -326,9 +327,9 @@ func saveFtpResult(info *common.HostInfo, target string, result *FtpScanResult)
|
||||
common.LogSuccess(successMsg)
|
||||
|
||||
// 保存结果
|
||||
vulnResult := &common.ScanResult{
|
||||
vulnResult := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
Details: details,
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
"net"
|
||||
"regexp"
|
||||
"strconv"
|
||||
@ -192,9 +193,9 @@ func read(text []byte, host string) error {
|
||||
}
|
||||
|
||||
// 保存扫描结果
|
||||
result := &common.ScanResult{
|
||||
result := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.SERVICE,
|
||||
Type: output.TypeService,
|
||||
Target: host,
|
||||
Status: "identified",
|
||||
Details: details,
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
)
|
||||
|
||||
// IMAPCredential 表示一个IMAP凭据
|
||||
@ -309,9 +310,9 @@ func saveIMAPResult(info *common.HostInfo, target string, credential IMAPCredent
|
||||
common.LogSuccess(successMsg)
|
||||
|
||||
// 保存结果
|
||||
vulnResult := &common.ScanResult{
|
||||
vulnResult := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
Details: map[string]interface{}{
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"github.com/IBM/sarama"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@ -45,9 +46,9 @@ func KafkaScan(info *common.HostInfo) error {
|
||||
common.LogSuccess(fmt.Sprintf("Kafka服务 %s 无需认证即可访问", target))
|
||||
|
||||
// 保存无认证访问结果
|
||||
result := &common.ScanResult{
|
||||
result := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
Details: map[string]interface{}{
|
||||
@ -79,9 +80,9 @@ func KafkaScan(info *common.HostInfo) error {
|
||||
result := concurrentKafkaScan(ctx, info, credentials, common.Timeout, common.MaxRetries)
|
||||
if result != nil {
|
||||
// 保存爆破成功结果
|
||||
vulnResult := &common.ScanResult{
|
||||
vulnResult := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
Details: map[string]interface{}{
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/go-ldap/ldap/v3"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
)
|
||||
|
||||
// LDAPCredential 表示一个LDAP凭据
|
||||
@ -296,9 +297,9 @@ func saveLDAPResult(info *common.HostInfo, target string, result *LDAPScanResult
|
||||
common.LogSuccess(successMsg)
|
||||
|
||||
// 保存结果
|
||||
vulnResult := &common.ScanResult{
|
||||
vulnResult := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
Details: details,
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
@ -218,9 +219,9 @@ func MS17010Scan(info *common.HostInfo) error {
|
||||
}
|
||||
|
||||
// 保存 MS17-010 漏洞结果
|
||||
result := &common.ScanResult{
|
||||
result := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: ip,
|
||||
Status: "vulnerable",
|
||||
Details: details,
|
||||
@ -248,9 +249,9 @@ func MS17010Scan(info *common.HostInfo) error {
|
||||
common.LogSuccess(fmt.Sprintf("发现后门 %s DOUBLEPULSAR", ip))
|
||||
|
||||
// 保存 DOUBLEPULSAR 后门结果
|
||||
backdoorResult := &common.ScanResult{
|
||||
backdoorResult := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: ip,
|
||||
Status: "backdoor",
|
||||
Details: map[string]interface{}{
|
||||
@ -270,9 +271,9 @@ func MS17010Scan(info *common.HostInfo) error {
|
||||
common.LogBase(fmt.Sprintf("系统信息 %s [%s]", ip, os))
|
||||
|
||||
// 保存系统信息
|
||||
sysResult := &common.ScanResult{
|
||||
sysResult := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.SERVICE,
|
||||
Type: output.TypeService,
|
||||
Target: ip,
|
||||
Status: "identified",
|
||||
Details: map[string]interface{}{
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
|
||||
mssql "github.com/denisenkom/go-mssqldb"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
)
|
||||
|
||||
// MSSQLProxyDialer 自定义dialer结构体
|
||||
@ -315,9 +316,9 @@ func saveMssqlResult(info *common.HostInfo, target string, credential MssqlCrede
|
||||
common.LogSuccess(successMsg)
|
||||
|
||||
// 保存结果
|
||||
vulnResult := &common.ScanResult{
|
||||
vulnResult := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
Details: map[string]interface{}{
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
@ -29,9 +30,9 @@ func MemcachedScan(info *common.HostInfo) error {
|
||||
|
||||
if result.Success {
|
||||
// 保存成功结果
|
||||
scanResult := &common.ScanResult{
|
||||
scanResult := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
Details: map[string]interface{}{
|
||||
|
@ -3,6 +3,7 @@
|
||||
package Plugins
|
||||
|
||||
import "github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
|
||||
func MiniDump(info *common.HostInfo) (err error) {
|
||||
return nil
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
)
|
||||
|
||||
// ModbusScanResult 表示 Modbus 扫描结果
|
||||
@ -251,9 +252,9 @@ func parseModbusResponse(response []byte) string {
|
||||
// saveModbusResult 保存Modbus扫描结果
|
||||
func saveModbusResult(info *common.HostInfo, target string, result *ModbusScanResult) {
|
||||
// 保存扫描结果
|
||||
scanResult := &common.ScanResult{
|
||||
scanResult := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
Details: map[string]interface{}{
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
)
|
||||
|
||||
// MongodbScan 执行MongoDB未授权扫描
|
||||
@ -53,9 +54,9 @@ func MongodbScan(info *common.HostInfo) error {
|
||||
common.LogSuccess(fmt.Sprintf("MongoDB %v 未授权访问", target))
|
||||
|
||||
// 保存未授权访问结果
|
||||
scanResult := &common.ScanResult{
|
||||
scanResult := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
Details: map[string]interface{}{
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
|
||||
"github.com/go-sql-driver/mysql"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
)
|
||||
|
||||
// MySQLProxyDialer 自定义dialer结构体
|
||||
@ -327,9 +328,9 @@ func saveMySQLResult(info *common.HostInfo, target string, credential MySQLCrede
|
||||
common.LogSuccess(successMsg)
|
||||
|
||||
// 保存结果
|
||||
vulnResult := &common.ScanResult{
|
||||
vulnResult := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
Details: map[string]interface{}{
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/neo4j/neo4j-go-driver/v4/neo4j"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
)
|
||||
|
||||
// Neo4jCredential 表示一个Neo4j凭据
|
||||
@ -349,9 +350,9 @@ func saveNeo4jResult(info *common.HostInfo, target string, result *Neo4jScanResu
|
||||
common.LogSuccess(successMsg)
|
||||
|
||||
// 保存结果
|
||||
vulnResult := &common.ScanResult{
|
||||
vulnResult := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
Details: details,
|
||||
|
@ -52,15 +52,7 @@ func NetBIOS(info *common.HostInfo) error {
|
||||
details["os_version"] = netbios.OsVersion
|
||||
}
|
||||
|
||||
scanResult := &common.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.SERVICE,
|
||||
Target: info.Host,
|
||||
Status: "identified",
|
||||
Details: details,
|
||||
}
|
||||
|
||||
common.SaveResult(scanResult)
|
||||
// NetBIOS信息已通过上面的LogSuccess记录,不需要额外保存结果
|
||||
return nil
|
||||
}
|
||||
return errNetBIOS
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
_ "github.com/sijms/go-ora/v2"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -417,9 +418,9 @@ func saveOracleResult(info *common.HostInfo, target string, credential OracleCre
|
||||
common.LogSuccess(successMsg)
|
||||
|
||||
// 保存结果
|
||||
vulnResult := &common.ScanResult{
|
||||
vulnResult := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
Details: map[string]interface{}{
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
)
|
||||
|
||||
// POP3Credential 表示一个POP3凭据
|
||||
@ -395,9 +396,9 @@ func savePOP3Result(info *common.HostInfo, target string, result *POP3ScanResult
|
||||
common.LogSuccess(successMsg)
|
||||
|
||||
// 保存结果
|
||||
vulnResult := &common.ScanResult{
|
||||
vulnResult := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
Details: map[string]interface{}{
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
|
||||
"github.com/lib/pq"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
)
|
||||
|
||||
// PostgresProxyDialer 自定义dialer结构体
|
||||
@ -302,9 +303,9 @@ func savePostgresResult(info *common.HostInfo, target string, credential Postgre
|
||||
common.LogSuccess(successMsg)
|
||||
|
||||
// 保存结果
|
||||
vulnResult := &common.ScanResult{
|
||||
vulnResult := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
Details: map[string]interface{}{
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
"github.com/tomatome/grdp/core"
|
||||
"github.com/tomatome/grdp/glog"
|
||||
"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
|
||||
}
|
||||
|
||||
vulnResult := &common.ScanResult{
|
||||
vulnResult := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
Details: details,
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
amqp "github.com/rabbitmq/amqp091-go"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -291,9 +292,9 @@ func saveRabbitMQResult(info *common.HostInfo, target string, credential RabbitM
|
||||
common.LogSuccess(successMsg)
|
||||
|
||||
// 保存结果
|
||||
vulnResult := &common.ScanResult{
|
||||
vulnResult := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
Details: map[string]interface{}{
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
@ -62,9 +63,9 @@ func RedisScan(info *common.HostInfo) error {
|
||||
common.LogSuccess(fmt.Sprintf("Redis无密码连接成功: %s", target))
|
||||
|
||||
// 保存未授权访问结果
|
||||
scanResult := &common.ScanResult{
|
||||
scanResult := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
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))
|
||||
|
||||
// 保存弱密码结果
|
||||
scanResult := &common.ScanResult{
|
||||
scanResult := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
Details: map[string]interface{}{
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
)
|
||||
|
||||
// RsyncCredential 表示一个Rsync凭据
|
||||
@ -465,9 +466,9 @@ func saveRsyncResult(info *common.HostInfo, target string, result *RsyncScanResu
|
||||
common.LogSuccess(successMsg)
|
||||
|
||||
// 保存结果
|
||||
vulnResult := &common.ScanResult{
|
||||
vulnResult := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
Details: details,
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
"github.com/stacktitan/smb/smb"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -242,9 +243,9 @@ func saveSmbResult(info *common.HostInfo, target string, credential SmbCredentia
|
||||
common.LogSuccess(successMsg)
|
||||
|
||||
// 保存结果
|
||||
result := &common.ScanResult{
|
||||
result := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
Details: details,
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
|
||||
"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(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "success",
|
||||
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(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "shares-found",
|
||||
Details: map[string]interface{}{
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
)
|
||||
|
||||
// SmtpCredential 表示一个SMTP凭据
|
||||
@ -314,9 +315,9 @@ func saveSmtpResult(info *common.HostInfo, target string, result *SmtpScanResult
|
||||
common.LogSuccess(successMsg)
|
||||
|
||||
// 保存结果
|
||||
vulnResult := &common.ScanResult{
|
||||
vulnResult := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
Details: details,
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"github.com/gosnmp/gosnmp"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@ -66,9 +67,9 @@ func SNMPScan(info *common.HostInfo) (tmperr error) {
|
||||
common.LogSuccess(successMsg)
|
||||
|
||||
// 保存结果
|
||||
vulnResult := &common.ScanResult{
|
||||
vulnResult := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
Details: map[string]interface{}{
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
@ -348,9 +349,9 @@ func logAndSaveSuccess(info *common.HostInfo, target string, result *SshScanResu
|
||||
|
||||
common.LogSuccess(successMsg)
|
||||
|
||||
vulnResult := &common.ScanResult{
|
||||
vulnResult := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
Details: details,
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
)
|
||||
|
||||
// TelnetCredential 表示一个Telnet凭据
|
||||
@ -313,9 +314,9 @@ func saveTelnetResult(info *common.HostInfo, target string, result *TelnetScanRe
|
||||
common.LogSuccess(successMsg)
|
||||
|
||||
// 保存结果
|
||||
vulnResult := &common.ScanResult{
|
||||
vulnResult := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
Details: details,
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/mitchellh/go-vnc"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
)
|
||||
|
||||
// VncCredential 表示VNC凭据
|
||||
@ -257,9 +258,9 @@ func saveVncResult(info *common.HostInfo, target string, credential VncCredentia
|
||||
common.LogSuccess(successLog)
|
||||
|
||||
// 保存结果
|
||||
vulnResult := &common.ScanResult{
|
||||
vulnResult := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: info.Host,
|
||||
Status: "vulnerable",
|
||||
Details: map[string]interface{}{
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
"github.com/shadow1ng/fscan/webscan"
|
||||
"github.com/shadow1ng/fscan/webscan/lib"
|
||||
"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(),
|
||||
Type: common.SERVICE,
|
||||
Type: output.TypeService,
|
||||
Target: info.Host,
|
||||
Status: "identified",
|
||||
Details: map[string]interface{}{
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/config"
|
||||
"github.com/shadow1ng/fscan/webscan/lib"
|
||||
)
|
||||
|
||||
@ -72,13 +73,13 @@ func WebScan(info *common.HostInfo) {
|
||||
// 根据扫描策略执行POC
|
||||
if common.Pocinfo.PocName == "" && len(info.Infostr) == 0 {
|
||||
// 执行所有POC
|
||||
executePOCs(ctx, common.PocInfo{Target: target})
|
||||
executePOCs(ctx, config.PocInfo{Target: target})
|
||||
} else if len(info.Infostr) > 0 {
|
||||
// 基于指纹信息执行POC
|
||||
scanByFingerprints(ctx, target, info.Infostr)
|
||||
} else if common.Pocinfo.PocName != "" {
|
||||
// 基于指定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
|
||||
}
|
||||
|
||||
executePOCs(ctx, common.PocInfo{Target: target, PocName: pocName})
|
||||
executePOCs(ctx, config.PocInfo{Target: target, PocName: pocName})
|
||||
}
|
||||
}
|
||||
|
||||
// executePOCs 执行POC检测
|
||||
func executePOCs(ctx context.Context, pocInfo common.PocInfo) {
|
||||
func executePOCs(ctx context.Context, pocInfo config.PocInfo) {
|
||||
// 验证目标
|
||||
if pocInfo.Target == "" {
|
||||
common.LogError(ErrEmptyTarget.Error())
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"github.com/google/cel-go/cel"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/output"
|
||||
"github.com/shadow1ng/fscan/webscan/info"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
@ -90,9 +91,9 @@ func CheckMultiPoc(req *http.Request, pocs []*Poc, workers int) {
|
||||
}
|
||||
|
||||
// 创建并保存扫描结果
|
||||
result := &common.ScanResult{
|
||||
result := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: task.Req.URL.String(),
|
||||
Status: "vulnerable",
|
||||
Details: details,
|
||||
@ -495,9 +496,9 @@ func clusterpoc(oReq *http.Request, p *Poc, variableMap map[string]interface{},
|
||||
|
||||
// 保存漏洞结果(除非明确指示跳过)
|
||||
if !skipSave {
|
||||
result := &common.ScanResult{
|
||||
result := &output.ScanResult{
|
||||
Time: time.Now(),
|
||||
Type: common.VULN,
|
||||
Type: output.TypeVuln,
|
||||
Target: targetURL,
|
||||
Status: "vulnerable",
|
||||
Details: details,
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"golang.org/x/net/proxy"
|
||||
"github.com/shadow1ng/fscan/common/proxy"
|
||||
"gopkg.in/yaml.v2"
|
||||
"net"
|
||||
"net/http"
|
||||
@ -67,15 +67,17 @@ func InitHttpClient(ThreadsNum int, DownProxy string, Timeout time.Duration) err
|
||||
|
||||
// 配置Socks5代理
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
if contextDialer, ok := dialSocksProxy.(proxy.ContextDialer); ok {
|
||||
tr.DialContext = contextDialer.DialContext
|
||||
} else {
|
||||
return errors.New("无法转换为DialContext类型")
|
||||
}
|
||||
tr.DialContext = proxyDialer.DialContext
|
||||
} else if DownProxy != "" {
|
||||
// 处理其他代理配置
|
||||
if DownProxy == "1" {
|
||||
|
Loading…
Reference in New Issue
Block a user