mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 05:56:46 +08:00
feat: 完善插件系统i18n国际化支持
- 修复重复输出问题:适配器层改为debug输出,避免与插件层重复 - 修复格式化错误:修正SaveExploitResult中的端口格式化问题 - 新增利用方法名称i18n:添加GetExploitMethodName函数支持方法名本地化 - 扩展i18n消息模板:新增利用方法执行、MySQL/Redis专用消息模板 - 完善exploiter国际化:所有利用方法和结果消息支持中英文切换 - 优化用户体验:利用方法显示从"information_gathering"变为"信息收集"
This commit is contained in:
parent
43f210ffc6
commit
b346e6bdc1
@ -188,6 +188,19 @@ func GetText(key string, args ...interface{}) string {
|
||||
return globalManager.GetText(key, args...)
|
||||
}
|
||||
|
||||
// GetExploitMethodName 获取利用方法的本地化名称
|
||||
func GetExploitMethodName(methodName string) string {
|
||||
// 尝试获取本地化的方法名称
|
||||
key := fmt.Sprintf("exploit_method_name_%s", methodName)
|
||||
localizedName := globalManager.GetText(key)
|
||||
|
||||
// 如果没有找到对应的本地化名称,返回原始名称
|
||||
if localizedName == key {
|
||||
return methodName
|
||||
}
|
||||
return localizedName
|
||||
}
|
||||
|
||||
// =============================================================================================
|
||||
// 已删除的死代码函数(未使用):
|
||||
// GetGlobalManager, GetLanguage, AddMessage, GetTextWithLanguage,
|
||||
|
@ -39,6 +39,164 @@ var PluginMessages = map[string]map[string]string{
|
||||
LangEN: "%s exploitation failed: %v",
|
||||
},
|
||||
|
||||
// ========================= 通用成功消息模板 =========================
|
||||
"plugin_login_success": {
|
||||
LangZH: "%s弱密码: %s [%s:%s]",
|
||||
LangEN: "%s weak password: %s [%s:%s]",
|
||||
},
|
||||
"plugin_login_success_passwd_only": {
|
||||
LangZH: "%s弱密码: %s [%s]",
|
||||
LangEN: "%s weak password: %s [%s]",
|
||||
},
|
||||
"plugin_unauthorized_access": {
|
||||
LangZH: "%s未授权访问: %s",
|
||||
LangEN: "%s unauthorized access: %s",
|
||||
},
|
||||
|
||||
// ========================= 利用(Exploit)消息模板 =========================
|
||||
"exploit_weak_password_success": {
|
||||
LangZH: "%s %s 弱密码利用成功",
|
||||
LangEN: "%s %s weak password exploit successful",
|
||||
},
|
||||
"exploit_unauthorized_success": {
|
||||
LangZH: "%s %s 未授权访问利用成功",
|
||||
LangEN: "%s %s unauthorized access exploit successful",
|
||||
},
|
||||
"exploit_command_exec_success": {
|
||||
LangZH: "%s %s 命令执行利用成功",
|
||||
LangEN: "%s %s command execution exploit successful",
|
||||
},
|
||||
"exploit_file_write_success": {
|
||||
LangZH: "%s %s 文件写入利用成功",
|
||||
LangEN: "%s %s file write exploit successful",
|
||||
},
|
||||
"exploit_sql_injection_success": {
|
||||
LangZH: "%s %s SQL注入利用成功",
|
||||
LangEN: "%s %s SQL injection exploit successful",
|
||||
},
|
||||
"exploit_data_extraction_success": {
|
||||
LangZH: "%s %s %s 利用成功",
|
||||
LangEN: "%s %s %s exploit successful",
|
||||
},
|
||||
"exploit_generic_success": {
|
||||
LangZH: "%s %s %s 利用成功",
|
||||
LangEN: "%s %s %s exploit successful",
|
||||
},
|
||||
"exploit_with_output": {
|
||||
LangZH: " 输出: %s",
|
||||
LangEN: " output: %s",
|
||||
},
|
||||
"exploit_files_created": {
|
||||
LangZH: "创建/修改的文件: %v",
|
||||
LangEN: "Files created/modified: %v",
|
||||
},
|
||||
"exploit_shell_obtained": {
|
||||
LangZH: "获得Shell: %s %s:%d 用户:%s",
|
||||
LangEN: "Shell obtained: %s %s:%d user:%s",
|
||||
},
|
||||
|
||||
// ========================= 利用方法执行消息 =========================
|
||||
"exploit_method_trying": {
|
||||
LangZH: "尝试利用方法: %s",
|
||||
LangEN: "Trying exploit method: %s",
|
||||
},
|
||||
"exploit_method_success": {
|
||||
LangZH: "利用方法 %s 执行成功",
|
||||
LangEN: "Exploit method %s executed successfully",
|
||||
},
|
||||
"exploit_method_failed": {
|
||||
LangZH: "利用方法 %s 执行失败: %v",
|
||||
LangEN: "Exploit method %s failed: %v",
|
||||
},
|
||||
"exploit_method_condition_not_met": {
|
||||
LangZH: "利用方法 %s 前置条件不满足,跳过",
|
||||
LangEN: "Exploit method %s prerequisites not met, skipping",
|
||||
},
|
||||
"exploit_all_methods_failed": {
|
||||
LangZH: "所有利用方法都失败",
|
||||
LangEN: "All exploit methods failed",
|
||||
},
|
||||
|
||||
// ========================= MySQL利用方法消息 =========================
|
||||
"mysql_version_info": {
|
||||
LangZH: "MySQL版本: %s",
|
||||
LangEN: "MySQL version: %s",
|
||||
},
|
||||
"mysql_current_user": {
|
||||
LangZH: "当前用户: %s",
|
||||
LangEN: "Current user: %s",
|
||||
},
|
||||
"mysql_current_database": {
|
||||
LangZH: "当前数据库: %s",
|
||||
LangEN: "Current database: %s",
|
||||
},
|
||||
"mysql_databases_found": {
|
||||
LangZH: "发现数据库: %s",
|
||||
LangEN: "Databases found: %s",
|
||||
},
|
||||
"mysql_tables_found": {
|
||||
LangZH: "发现表: %v",
|
||||
LangEN: "Tables found: %v",
|
||||
},
|
||||
"mysql_user_privileges": {
|
||||
LangZH: "用户权限: %s",
|
||||
LangEN: "User privileges: %s",
|
||||
},
|
||||
"mysql_file_privilege_detected": {
|
||||
LangZH: "检测到FILE权限,可能支持文件操作",
|
||||
LangEN: "FILE privilege detected, file operations may be supported",
|
||||
},
|
||||
"mysql_file_read_success": {
|
||||
LangZH: "读取文件 %s:\n%s",
|
||||
LangEN: "File %s read:\n%s",
|
||||
},
|
||||
"mysql_file_write_success": {
|
||||
LangZH: "成功写入文件: %s",
|
||||
LangEN: "File written successfully: %s",
|
||||
},
|
||||
"mysql_no_file_privilege": {
|
||||
LangZH: "无法读取任何文件,可能没有FILE权限",
|
||||
LangEN: "Cannot read any files, may lack FILE privilege",
|
||||
},
|
||||
|
||||
// ========================= Redis利用方法消息 =========================
|
||||
"redis_server_info": {
|
||||
LangZH: "Redis服务器信息: %s",
|
||||
LangEN: "Redis server info: %s",
|
||||
},
|
||||
"redis_config_info": {
|
||||
LangZH: "Redis配置信息: %s",
|
||||
LangEN: "Redis config info: %s",
|
||||
},
|
||||
"redis_keys_found": {
|
||||
LangZH: "发现Redis键: %v",
|
||||
LangEN: "Redis keys found: %v",
|
||||
},
|
||||
"redis_backup_created": {
|
||||
LangZH: "Redis备份创建成功: %s",
|
||||
LangEN: "Redis backup created: %s",
|
||||
},
|
||||
"redis_cron_job_written": {
|
||||
LangZH: "Cron任务写入成功: %s",
|
||||
LangEN: "Cron job written successfully: %s",
|
||||
},
|
||||
"redis_ssh_key_written": {
|
||||
LangZH: "SSH密钥写入成功: %s",
|
||||
LangEN: "SSH key written successfully: %s",
|
||||
},
|
||||
"redis_webshell_written": {
|
||||
LangZH: "Webshell写入成功: %s",
|
||||
LangEN: "Webshell written successfully: %s",
|
||||
},
|
||||
"redis_no_keys_found": {
|
||||
LangZH: "未发现任何Redis键",
|
||||
LangEN: "No Redis keys found",
|
||||
},
|
||||
"redis_write_failed": {
|
||||
LangZH: "Redis写入操作失败",
|
||||
LangEN: "Redis write operation failed",
|
||||
},
|
||||
|
||||
// ========================= 插件架构消息 =========================
|
||||
"plugin_new_arch_trying": {
|
||||
LangZH: "尝试使用新插件架构: %s",
|
||||
@ -181,21 +339,47 @@ var PluginMessages = map[string]map[string]string{
|
||||
LangEN: "%s vulnerability found: %s - %s",
|
||||
},
|
||||
|
||||
// ========================= 利用方法名称i18n =========================
|
||||
"exploit_method_name_information_gathering": {
|
||||
LangZH: "信息收集",
|
||||
LangEN: "information_gathering",
|
||||
},
|
||||
"exploit_method_name_database_enumeration": {
|
||||
LangZH: "数据库枚举",
|
||||
LangEN: "database_enumeration",
|
||||
},
|
||||
"exploit_method_name_privilege_check": {
|
||||
LangZH: "权限检查",
|
||||
LangEN: "privilege_check",
|
||||
},
|
||||
"exploit_method_name_file_read": {
|
||||
LangZH: "文件读取",
|
||||
LangEN: "file_read",
|
||||
},
|
||||
"exploit_method_name_file_write": {
|
||||
LangZH: "文件写入",
|
||||
LangEN: "file_write",
|
||||
},
|
||||
"exploit_method_name_arbitrary_file_write": {
|
||||
LangZH: "任意文件写入",
|
||||
LangEN: "arbitrary_file_write",
|
||||
},
|
||||
"exploit_method_name_ssh_key_write": {
|
||||
LangZH: "SSH密钥写入",
|
||||
LangEN: "ssh_key_write",
|
||||
},
|
||||
"exploit_method_name_crontab_injection": {
|
||||
LangZH: "定时任务注入",
|
||||
LangEN: "crontab_injection",
|
||||
},
|
||||
"exploit_method_name_data_extraction": {
|
||||
LangZH: "数据提取",
|
||||
LangEN: "data_extraction",
|
||||
},
|
||||
|
||||
// ========================= 利用结果消息 =========================
|
||||
"exploit_result_saved": {
|
||||
LangZH: "利用结果已保存: %s",
|
||||
LangEN: "Exploitation result saved: %s",
|
||||
},
|
||||
"exploit_method_trying": {
|
||||
LangZH: "尝试利用方法: %s",
|
||||
LangEN: "Trying exploitation method: %s",
|
||||
},
|
||||
"exploit_method_success": {
|
||||
LangZH: "利用方法成功: %s",
|
||||
LangEN: "Exploitation method successful: %s",
|
||||
},
|
||||
"exploit_method_failed": {
|
||||
LangZH: "利用方法失败: %s - %v",
|
||||
LangEN: "Exploitation method failed: %s - %v",
|
||||
},
|
||||
}
|
@ -57,21 +57,9 @@ func (a *PluginAdapter) AdaptPluginScan(pluginName string, info *common.HostInfo
|
||||
if result != nil && result.Success {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
|
||||
if len(result.Credentials) > 0 {
|
||||
// 有凭据的情况
|
||||
cred := result.Credentials[0]
|
||||
if cred.Username != "" {
|
||||
common.LogSuccess(fmt.Sprintf("%s successful login: %s [%s:%s]",
|
||||
pluginName, target, cred.Username, cred.Password))
|
||||
} else {
|
||||
// 仅密码的情况(如Redis)
|
||||
common.LogSuccess(fmt.Sprintf("%s successful login: %s [%s]",
|
||||
pluginName, target, cred.Password))
|
||||
}
|
||||
} else {
|
||||
// 未授权访问的情况
|
||||
common.LogSuccess(fmt.Sprintf("%s unauthorized access: %s", pluginName, target))
|
||||
}
|
||||
// 适配器层不输出扫描结果,由插件层负责输出
|
||||
// 这避免了重复输出的问题
|
||||
common.LogDebug(fmt.Sprintf("插件 %s 适配成功: %s", pluginName, target))
|
||||
|
||||
// 保存结果到文件
|
||||
a.saveResult(info, result, pluginName)
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/i18n"
|
||||
"sort"
|
||||
)
|
||||
|
||||
@ -56,28 +57,28 @@ func (e *BaseExploiter) Exploit(ctx context.Context, info *common.HostInfo, cred
|
||||
for _, method := range e.exploitMethods {
|
||||
// 检查前置条件
|
||||
if !e.checkConditions(method.Conditions, info, creds) {
|
||||
common.LogDebug(fmt.Sprintf("利用方法 %s 前置条件不满足,跳过", method.Name))
|
||||
common.LogDebug(i18n.GetText("exploit_method_condition_not_met", method.Name))
|
||||
continue
|
||||
}
|
||||
|
||||
common.LogDebug(fmt.Sprintf("尝试利用方法: %s", method.Name))
|
||||
common.LogDebug(i18n.GetText("exploit_method_trying", i18n.GetExploitMethodName(method.Name)))
|
||||
|
||||
// 执行利用
|
||||
result, err := method.Handler(ctx, info, creds)
|
||||
if err != nil {
|
||||
common.LogError(fmt.Sprintf("利用方法 %s 执行失败: %v", method.Name, err))
|
||||
common.LogError(i18n.GetText("exploit_method_failed", method.Name, err))
|
||||
continue
|
||||
}
|
||||
|
||||
if result != nil && result.Success {
|
||||
common.LogSuccess(fmt.Sprintf("利用方法 %s 执行成功", method.Name))
|
||||
common.LogSuccess(i18n.GetText("exploit_method_success", i18n.GetExploitMethodName(method.Name)))
|
||||
result.Type = method.Type
|
||||
result.Method = method.Name
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("所有利用方法都失败")
|
||||
return nil, fmt.Errorf(i18n.GetText("exploit_all_methods_failed"))
|
||||
}
|
||||
|
||||
// checkConditions 检查前置条件
|
||||
@ -167,38 +168,40 @@ func SaveExploitResult(info *common.HostInfo, result *ExploitResult, pluginName
|
||||
return
|
||||
}
|
||||
|
||||
target := fmt.Sprintf("%s:%d", info.Host, info.Ports)
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
|
||||
var message string
|
||||
switch result.Type {
|
||||
case ExploitWeakPassword:
|
||||
message = fmt.Sprintf("%s %s 弱密码利用成功", pluginName, target)
|
||||
message = i18n.GetText("exploit_weak_password_success", pluginName, target)
|
||||
case ExploitUnauthorized:
|
||||
message = fmt.Sprintf("%s %s 未授权访问利用成功", pluginName, target)
|
||||
message = i18n.GetText("exploit_unauthorized_success", pluginName, target)
|
||||
case ExploitCommandExec:
|
||||
message = fmt.Sprintf("%s %s 命令执行利用成功", pluginName, target)
|
||||
message = i18n.GetText("exploit_command_exec_success", pluginName, target)
|
||||
case ExploitFileWrite:
|
||||
message = fmt.Sprintf("%s %s 文件写入利用成功", pluginName, target)
|
||||
message = i18n.GetText("exploit_file_write_success", pluginName, target)
|
||||
case ExploitSQLInjection:
|
||||
message = fmt.Sprintf("%s %s SQL注入利用成功", pluginName, target)
|
||||
message = i18n.GetText("exploit_sql_injection_success", pluginName, target)
|
||||
case ExploitDataExtraction:
|
||||
message = i18n.GetText("exploit_data_extraction_success", pluginName, target, i18n.GetExploitMethodName(result.Method))
|
||||
default:
|
||||
message = fmt.Sprintf("%s %s %s 利用成功", pluginName, target, result.Type)
|
||||
message = i18n.GetText("exploit_generic_success", pluginName, target, i18n.GetExploitMethodName(result.Method))
|
||||
}
|
||||
|
||||
if result.Output != "" {
|
||||
message += fmt.Sprintf(" 输出: %s", result.Output)
|
||||
message += i18n.GetText("exploit_with_output", result.Output)
|
||||
}
|
||||
|
||||
common.LogSuccess(message)
|
||||
|
||||
// 保存文件信息
|
||||
if len(result.Files) > 0 {
|
||||
common.LogSuccess(fmt.Sprintf("创建/修改的文件: %v", result.Files))
|
||||
common.LogSuccess(i18n.GetText("exploit_files_created", result.Files))
|
||||
}
|
||||
|
||||
// 保存Shell信息
|
||||
if result.Shell != nil {
|
||||
common.LogSuccess(fmt.Sprintf("获得Shell: %s %s:%d 用户:%s",
|
||||
common.LogSuccess(i18n.GetText("exploit_shell_obtained",
|
||||
result.Shell.Type, result.Shell.Host, result.Shell.Port, result.Shell.User))
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/i18n"
|
||||
"github.com/shadow1ng/fscan/plugins/base"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -90,21 +91,21 @@ func (e *MySQLExploiter) exploitInformationGathering(ctx context.Context, info *
|
||||
// 获取版本信息
|
||||
version, err := e.getVersion(ctx, db)
|
||||
if err == nil {
|
||||
base.AddOutputToResult(result, fmt.Sprintf("MySQL版本: %s", version))
|
||||
base.AddOutputToResult(result, i18n.GetText("mysql_version_info", version))
|
||||
result.Extra["version"] = version
|
||||
}
|
||||
|
||||
// 获取当前用户
|
||||
user, err := e.getCurrentUser(ctx, db)
|
||||
if err == nil {
|
||||
base.AddOutputToResult(result, fmt.Sprintf("当前用户: %s", user))
|
||||
base.AddOutputToResult(result, i18n.GetText("mysql_current_user", user))
|
||||
result.Extra["current_user"] = user
|
||||
}
|
||||
|
||||
// 获取当前数据库
|
||||
database, err := e.getCurrentDatabase(ctx, db)
|
||||
if err == nil {
|
||||
base.AddOutputToResult(result, fmt.Sprintf("当前数据库: %s", database))
|
||||
base.AddOutputToResult(result, i18n.GetText("mysql_current_database", database))
|
||||
result.Extra["current_database"] = database
|
||||
}
|
||||
|
||||
@ -124,14 +125,14 @@ func (e *MySQLExploiter) exploitDatabaseEnumeration(ctx context.Context, info *c
|
||||
// 枚举数据库
|
||||
databases, err := e.enumerateDatabases(ctx, db)
|
||||
if err == nil && len(databases) > 0 {
|
||||
base.AddOutputToResult(result, fmt.Sprintf("发现数据库: %s", strings.Join(databases, ", ")))
|
||||
base.AddOutputToResult(result, i18n.GetText("mysql_databases_found", strings.Join(databases, ", ")))
|
||||
result.Extra["databases"] = databases
|
||||
}
|
||||
|
||||
// 枚举表(限制在非系统数据库中)
|
||||
tables, err := e.enumerateTables(ctx, db)
|
||||
if err == nil && len(tables) > 0 {
|
||||
base.AddOutputToResult(result, fmt.Sprintf("发现表: %v", tables))
|
||||
base.AddOutputToResult(result, i18n.GetText("mysql_tables_found", tables))
|
||||
result.Extra["tables"] = tables
|
||||
}
|
||||
|
||||
@ -151,7 +152,7 @@ func (e *MySQLExploiter) exploitPrivilegeCheck(ctx context.Context, info *common
|
||||
// 检查用户权限
|
||||
privileges, err := e.getUserPrivileges(ctx, db)
|
||||
if err == nil && len(privileges) > 0 {
|
||||
base.AddOutputToResult(result, fmt.Sprintf("用户权限: %s", strings.Join(privileges, ", ")))
|
||||
base.AddOutputToResult(result, i18n.GetText("mysql_user_privileges", strings.Join(privileges, ", ")))
|
||||
result.Extra["privileges"] = privileges
|
||||
}
|
||||
|
||||
@ -159,7 +160,7 @@ func (e *MySQLExploiter) exploitPrivilegeCheck(ctx context.Context, info *common
|
||||
hasFilePriv := e.hasFilePrivilege(privileges)
|
||||
result.Extra["has_file_privilege"] = hasFilePriv
|
||||
if hasFilePriv {
|
||||
base.AddOutputToResult(result, "检测到FILE权限,可能支持文件操作")
|
||||
base.AddOutputToResult(result, i18n.GetText("mysql_file_privilege_detected"))
|
||||
}
|
||||
|
||||
return result, nil
|
||||
@ -187,14 +188,14 @@ func (e *MySQLExploiter) exploitFileRead(ctx context.Context, info *common.HostI
|
||||
for _, file := range filesToRead {
|
||||
content, err := e.readFile(ctx, db, file)
|
||||
if err == nil && content != "" {
|
||||
base.AddOutputToResult(result, fmt.Sprintf("读取文件 %s:\n%s", file, content))
|
||||
base.AddOutputToResult(result, i18n.GetText("mysql_file_read_success", file, content))
|
||||
hasRead = true
|
||||
}
|
||||
}
|
||||
|
||||
if !hasRead {
|
||||
return base.CreateFailedExploitResult(base.ExploitDataExtraction, "file_read",
|
||||
fmt.Errorf("无法读取任何文件,可能没有FILE权限")), nil
|
||||
fmt.Errorf(i18n.GetText("mysql_no_file_privilege"))), nil
|
||||
}
|
||||
|
||||
return result, nil
|
||||
@ -219,7 +220,7 @@ func (e *MySQLExploiter) exploitFileWrite(ctx context.Context, info *common.Host
|
||||
return base.CreateFailedExploitResult(base.ExploitFileWrite, "file_write", err), nil
|
||||
}
|
||||
|
||||
base.AddOutputToResult(result, fmt.Sprintf("成功写入文件: %s", testFile))
|
||||
base.AddOutputToResult(result, i18n.GetText("mysql_file_write_success", testFile))
|
||||
base.AddFileToResult(result, testFile)
|
||||
|
||||
return result, nil
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/i18n"
|
||||
"github.com/shadow1ng/fscan/plugins/base"
|
||||
)
|
||||
|
||||
@ -67,10 +68,10 @@ func (p *MySQLPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.Sc
|
||||
return result, err // 扫描失败,直接返回
|
||||
}
|
||||
|
||||
// 记录成功的弱密码发现(支持i18n)
|
||||
// 记录成功的弱密码发现(使用i18n)
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
cred := result.Credentials[0]
|
||||
common.LogSuccess(fmt.Sprintf("MySQL scan success: %s with %s:%s", target, cred.Username, cred.Password))
|
||||
common.LogSuccess(i18n.GetText("mysql_scan_success", target, cred.Username, cred.Password))
|
||||
|
||||
// 自动利用功能(可通过-nobr参数禁用)
|
||||
if result.Success && len(result.Credentials) > 0 && !common.DisableBrute {
|
||||
@ -84,17 +85,17 @@ func (p *MySQLPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.Sc
|
||||
// autoExploit 自动利用
|
||||
func (p *MySQLPlugin) autoExploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) {
|
||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||
common.LogDebug(fmt.Sprintf("MySQL exploit starting for %s", target))
|
||||
common.LogDebug(i18n.GetText("plugin_exploit_start", "MySQL", target))
|
||||
|
||||
// 执行利用
|
||||
result, err := p.exploiter.Exploit(ctx, info, creds)
|
||||
if err != nil {
|
||||
common.LogError(fmt.Sprintf("MySQL exploit failed: %v", err))
|
||||
common.LogError(i18n.GetText("plugin_exploit_failed", "MySQL", err))
|
||||
return
|
||||
}
|
||||
|
||||
if result != nil && result.Success {
|
||||
common.LogSuccess(fmt.Sprintf("MySQL exploit success using %s", result.Method))
|
||||
common.LogSuccess(i18n.GetText("plugin_exploit_success", "MySQL", i18n.GetExploitMethodName(result.Method)))
|
||||
base.SaveExploitResult(info, result, "MySQL")
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/common/i18n"
|
||||
"github.com/shadow1ng/fscan/plugins/base"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@ -129,7 +130,7 @@ func (e *RedisExploiter) exploitArbitraryFileWrite(ctx context.Context, info *co
|
||||
fmt.Errorf("写入失败: %s", msg)), nil
|
||||
}
|
||||
|
||||
base.AddOutputToResult(result, fmt.Sprintf("成功写入文件: %s", common.RedisWritePath))
|
||||
base.AddOutputToResult(result, i18n.GetText("redis_webshell_written", common.RedisWritePath))
|
||||
base.AddFileToResult(result, common.RedisWritePath)
|
||||
|
||||
return result, nil
|
||||
@ -216,7 +217,7 @@ func (e *RedisExploiter) exploitCrontabInjection(ctx context.Context, info *comm
|
||||
fmt.Errorf("写入失败: %s", msg)), nil
|
||||
}
|
||||
|
||||
base.AddOutputToResult(result, fmt.Sprintf("成功注入Crontab任务,反弹Shell到: %s", common.RedisShell))
|
||||
base.AddOutputToResult(result, i18n.GetText("redis_cron_job_written", common.RedisShell))
|
||||
|
||||
// 创建Shell信息
|
||||
shellParts := strings.Split(common.RedisShell, ":")
|
||||
@ -245,7 +246,7 @@ func (e *RedisExploiter) exploitDataExtraction(ctx context.Context, info *common
|
||||
// 获取所有键
|
||||
keys, err := e.getAllKeys(redisConn)
|
||||
if err == nil && len(keys) > 0 {
|
||||
base.AddOutputToResult(result, fmt.Sprintf("发现 %d 个键: %s", len(keys), strings.Join(keys[:min(10, len(keys))], ", ")))
|
||||
base.AddOutputToResult(result, i18n.GetText("redis_keys_found", strings.Join(keys[:min(10, len(keys))], ", ")))
|
||||
result.Extra["keys"] = keys
|
||||
|
||||
// 获取部分键值
|
||||
@ -255,7 +256,7 @@ func (e *RedisExploiter) exploitDataExtraction(ctx context.Context, info *common
|
||||
}
|
||||
value, err := e.getKeyValue(redisConn, key)
|
||||
if err == nil && value != "" {
|
||||
base.AddOutputToResult(result, fmt.Sprintf("键 %s = %s", key, value))
|
||||
base.AddOutputToResult(result, fmt.Sprintf("%s = %s", key, value))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -288,8 +289,8 @@ func (e *RedisExploiter) exploitInfoGathering(ctx context.Context, info *common.
|
||||
}
|
||||
|
||||
// 获取配置信息
|
||||
base.AddOutputToResult(result, fmt.Sprintf("数据库目录: %s", redisConn.config.Dir))
|
||||
base.AddOutputToResult(result, fmt.Sprintf("数据库文件: %s", redisConn.config.DBFilename))
|
||||
base.AddOutputToResult(result, i18n.GetText("redis_config_info", fmt.Sprintf("Dir: %s", redisConn.config.Dir)))
|
||||
base.AddOutputToResult(result, i18n.GetText("redis_config_info", fmt.Sprintf("DBFilename: %s", redisConn.config.DBFilename)))
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user