mirror of
https://github.com/shadow1ng/fscan.git
synced 2026-09-25 12:41:53 +08:00
refactor: 增强 systeminfo 插件并合并 envinfo
- systeminfo 新增网卡信息、权限检测、补丁数量、杀软检测、 防火墙状态、敏感环境变量扫描等功能 - 合并 envinfo 到 systeminfo,删除独立的 envinfo 插件 - 修复本地插件通过 -m 指定时仍需 -h 参数的问题 - 通过回调机制解决 common/plugins 循环依赖
This commit is contained in:
+10
-2
@@ -15,6 +15,9 @@ import (
|
|||||||
// ErrShowHelp 表示用户请求显示帮助(正常退出)
|
// ErrShowHelp 表示用户请求显示帮助(正常退出)
|
||||||
var ErrShowHelp = errors.New("show help requested")
|
var ErrShowHelp = errors.New("show help requested")
|
||||||
|
|
||||||
|
// IsLocalMode 由 plugins 包注册,判断 -m 指定的是否全是本地插件
|
||||||
|
var IsLocalMode func(mode string) bool
|
||||||
|
|
||||||
// Banner 显示程序横幅信息
|
// Banner 显示程序横幅信息
|
||||||
func Banner() {
|
func Banner() {
|
||||||
// 静默模式下完全跳过Banner显示
|
// 静默模式下完全跳过Banner显示
|
||||||
@@ -272,9 +275,14 @@ func shouldShowHelp(Info *HostInfo, fv *FlagVars) bool {
|
|||||||
// 检查是否提供了扫描目标
|
// 检查是否提供了扫描目标
|
||||||
hasTarget := Info.Host != "" || fv.TargetURL != "" || fv.HostsFile != "" || fv.URLsFile != ""
|
hasTarget := Info.Host != "" || fv.TargetURL != "" || fv.HostsFile != "" || fv.URLsFile != ""
|
||||||
|
|
||||||
// 本地模式需要指定插件才算有效目标
|
// 本地模式不需要目标主机
|
||||||
if fv.LocalPlugin != "" {
|
if fv.LocalPlugin != "" {
|
||||||
hasTarget = true
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// -m 指定的全是本地插件时也不需要目标
|
||||||
|
if IsLocalMode != nil && IsLocalMode(fv.ScanMode) {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果没有提供任何扫描目标,则显示帮助
|
// 如果没有提供任何扫描目标,则显示帮助
|
||||||
|
|||||||
@@ -693,6 +693,28 @@ systeminfo_distro_exists:
|
|||||||
other: "Distribution: /etc/os-release exists"
|
other: "Distribution: /etc/os-release exists"
|
||||||
systeminfo_whoami:
|
systeminfo_whoami:
|
||||||
other: "Current User (whoami): {{.Arg1}}"
|
other: "Current User (whoami): {{.Arg1}}"
|
||||||
|
systeminfo_iface:
|
||||||
|
other: "Interface {{.Arg1}}: {{.Arg2}} (MAC: {{.Arg3}})"
|
||||||
|
systeminfo_privilege:
|
||||||
|
other: "Privilege Level: {{.Arg1}}"
|
||||||
|
systeminfo_privilege_group:
|
||||||
|
other: "Admin Group: {{.Arg1}}"
|
||||||
|
systeminfo_id_info:
|
||||||
|
other: "User Info: {{.Arg1}}"
|
||||||
|
systeminfo_firewall:
|
||||||
|
other: "Firewall: {{.Arg1}}"
|
||||||
|
systeminfo_firewall_rules:
|
||||||
|
other: "Firewall Rules: {{.Arg1}}"
|
||||||
|
systeminfo_patches:
|
||||||
|
other: "Installed Patches: {{.Arg1}}"
|
||||||
|
systeminfo_antivirus:
|
||||||
|
other: "Antivirus Detected: {{.Arg1}}"
|
||||||
|
systeminfo_sudo:
|
||||||
|
other: "Sudo Privileges: {{.Arg1}}"
|
||||||
|
systeminfo_macos_detail:
|
||||||
|
other: "macOS: {{.Arg1}}"
|
||||||
|
systeminfo_sensitive_env:
|
||||||
|
other: "Sensitive Env Var: {{.Arg1}}={{.Arg2}}"
|
||||||
|
|
||||||
# Windows scheduled task
|
# Windows scheduled task
|
||||||
winschtask_success:
|
winschtask_success:
|
||||||
|
|||||||
@@ -693,6 +693,28 @@ systeminfo_distro_exists:
|
|||||||
other: "发行版: /etc/os-release 存在"
|
other: "发行版: /etc/os-release 存在"
|
||||||
systeminfo_whoami:
|
systeminfo_whoami:
|
||||||
other: "当前用户(whoami): {{.Arg1}}"
|
other: "当前用户(whoami): {{.Arg1}}"
|
||||||
|
systeminfo_iface:
|
||||||
|
other: "网卡 {{.Arg1}}: {{.Arg2}} (MAC: {{.Arg3}})"
|
||||||
|
systeminfo_privilege:
|
||||||
|
other: "权限级别: {{.Arg1}}"
|
||||||
|
systeminfo_privilege_group:
|
||||||
|
other: "所属管理组: {{.Arg1}}"
|
||||||
|
systeminfo_id_info:
|
||||||
|
other: "用户信息: {{.Arg1}}"
|
||||||
|
systeminfo_firewall:
|
||||||
|
other: "防火墙: {{.Arg1}}"
|
||||||
|
systeminfo_firewall_rules:
|
||||||
|
other: "防火墙规则数: {{.Arg1}}"
|
||||||
|
systeminfo_patches:
|
||||||
|
other: "已安装补丁: {{.Arg1}}个"
|
||||||
|
systeminfo_antivirus:
|
||||||
|
other: "检测到杀软: {{.Arg1}}"
|
||||||
|
systeminfo_sudo:
|
||||||
|
other: "sudo权限: {{.Arg1}}"
|
||||||
|
systeminfo_macos_detail:
|
||||||
|
other: "macOS: {{.Arg1}}"
|
||||||
|
systeminfo_sensitive_env:
|
||||||
|
other: "敏感环境变量: {{.Arg1}}={{.Arg2}}"
|
||||||
|
|
||||||
# Windows计划任务
|
# Windows计划任务
|
||||||
winschtask_success:
|
winschtask_success:
|
||||||
|
|||||||
+1
-19
@@ -6,7 +6,6 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
@@ -55,7 +54,7 @@ func determineScanMode(config *common.Config, state *common.State) ScanMode {
|
|||||||
return ScanModeAlive
|
return ScanModeAlive
|
||||||
case config.LocalMode:
|
case config.LocalMode:
|
||||||
return ScanModeLocal
|
return ScanModeLocal
|
||||||
case isAllLocalPlugins(config.Mode):
|
case common.IsLocalMode != nil && common.IsLocalMode(config.Mode):
|
||||||
config.LocalMode = true
|
config.LocalMode = true
|
||||||
config.LocalPlugin = config.Mode
|
config.LocalPlugin = config.Mode
|
||||||
return ScanModeLocal
|
return ScanModeLocal
|
||||||
@@ -66,23 +65,6 @@ func determineScanMode(config *common.Config, state *common.State) ScanMode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// isAllLocalPlugins 检查 -m 指定的插件是否全部为 local 类型
|
|
||||||
func isAllLocalPlugins(mode string) bool {
|
|
||||||
if mode == "" || mode == "all" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for _, name := range strings.Split(mode, ",") {
|
|
||||||
name = strings.TrimSpace(name)
|
|
||||||
if name == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !plugins.HasType(name, plugins.PluginTypeLocal) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// selectStrategy 根据扫描模式选择策略
|
// selectStrategy 根据扫描模式选择策略
|
||||||
func selectStrategy(config *common.Config, state *common.State, info common.HostInfo) ScanStrategy {
|
func selectStrategy(config *common.Config, state *common.State, info common.HostInfo) ScanStrategy {
|
||||||
mode := determineScanMode(config, state)
|
mode := determineScanMode(config, state)
|
||||||
|
|||||||
@@ -98,6 +98,24 @@ var (
|
|||||||
mutex sync.RWMutex
|
mutex sync.RWMutex
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
common.IsLocalMode = func(mode string) bool {
|
||||||
|
if mode == "" || mode == "all" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, name := range strings.Split(mode, ",") {
|
||||||
|
name = strings.TrimSpace(name)
|
||||||
|
if name == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !HasType(name, PluginTypeLocal) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// RegisterWithPorts 注册带端口信息的插件
|
// RegisterWithPorts 注册带端口信息的插件
|
||||||
func RegisterWithPorts(name string, factory func() Plugin, ports []int) {
|
func RegisterWithPorts(name string, factory func() Plugin, ports []int) {
|
||||||
RegisterWithTypes(name, factory, ports, []string{PluginTypeService})
|
RegisterWithTypes(name, factory, ports, []string{PluginTypeService})
|
||||||
|
|||||||
@@ -1,131 +0,0 @@
|
|||||||
//go:build (plugin_envinfo || !plugin_selective) && !no_local
|
|
||||||
|
|
||||||
package local
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
"github.com/shadow1ng/fscan/common/i18n"
|
|
||||||
"github.com/shadow1ng/fscan/plugins"
|
|
||||||
)
|
|
||||||
|
|
||||||
// EnvInfoPlugin 环境变量信息收集插件
|
|
||||||
// 设计哲学:"做一件事并做好"
|
|
||||||
// - 专注于环境变量收集
|
|
||||||
// - 过滤敏感信息关键词
|
|
||||||
// - 简单有效的实现
|
|
||||||
type EnvInfoPlugin struct {
|
|
||||||
plugins.BasePlugin
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewEnvInfoPlugin 创建环境变量信息插件
|
|
||||||
func NewEnvInfoPlugin() *EnvInfoPlugin {
|
|
||||||
return &EnvInfoPlugin{
|
|
||||||
BasePlugin: plugins.NewBasePlugin("envinfo"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scan 执行环境变量收集 - 直接、有效
|
|
||||||
func (p *EnvInfoPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *plugins.Result {
|
|
||||||
var output strings.Builder
|
|
||||||
var sensitiveVars []string
|
|
||||||
|
|
||||||
output.WriteString("=== 环境变量信息收集 ===\n")
|
|
||||||
|
|
||||||
// 获取所有环境变量
|
|
||||||
envs := os.Environ()
|
|
||||||
output.WriteString(fmt.Sprintf("总环境变量数: %d\n\n", len(envs)))
|
|
||||||
|
|
||||||
// 敏感关键词 - 直接硬编码,简单有效
|
|
||||||
sensitiveKeywords := []string{
|
|
||||||
"password", "passwd", "pwd", "secret", "key", "token",
|
|
||||||
"auth", "credential", "api", "access", "session",
|
|
||||||
"密码", "令牌", "密钥", "认证",
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重要环境变量 - 系统相关
|
|
||||||
importantVars := []string{
|
|
||||||
"PATH", "HOME", "USER", "USERNAME", "USERPROFILE", "TEMP", "TMP",
|
|
||||||
"HOMEPATH", "COMPUTERNAME", "USERDOMAIN", "PROCESSOR_ARCHITECTURE",
|
|
||||||
}
|
|
||||||
|
|
||||||
output.WriteString("=== 重要环境变量 ===\n")
|
|
||||||
for _, envVar := range importantVars {
|
|
||||||
if value := os.Getenv(envVar); value != "" {
|
|
||||||
// PATH特殊处理 - 只显示条目数
|
|
||||||
if envVar == "PATH" {
|
|
||||||
paths := strings.Split(value, string(os.PathListSeparator))
|
|
||||||
output.WriteString(fmt.Sprintf("%s: %d个路径\n", envVar, len(paths)))
|
|
||||||
} else {
|
|
||||||
output.WriteString(fmt.Sprintf("%s: %s\n", envVar, value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 扫描所有环境变量寻找敏感信息
|
|
||||||
output.WriteString("\n=== 潜在敏感环境变量 ===\n")
|
|
||||||
for _, env := range envs {
|
|
||||||
parts := strings.SplitN(env, "=", 2)
|
|
||||||
if len(parts) != 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
envName := strings.ToLower(parts[0])
|
|
||||||
envValue := parts[1]
|
|
||||||
|
|
||||||
// 检查是否包含敏感关键词
|
|
||||||
for _, keyword := range sensitiveKeywords {
|
|
||||||
if strings.Contains(envName, keyword) {
|
|
||||||
// 脱敏显示:只显示前几个字符
|
|
||||||
displayValue := envValue
|
|
||||||
if len(envValue) > 10 {
|
|
||||||
displayValue = envValue[:10] + "..."
|
|
||||||
}
|
|
||||||
|
|
||||||
sensitiveInfo := fmt.Sprintf("%s: %s", parts[0], displayValue)
|
|
||||||
sensitiveVars = append(sensitiveVars, sensitiveInfo)
|
|
||||||
output.WriteString(sensitiveInfo + "\n")
|
|
||||||
common.LogSuccess(i18n.Tr("envinfo_sensitive", parts[0]))
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(sensitiveVars) == 0 {
|
|
||||||
output.WriteString("未发现明显的敏感环境变量\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 统计信息
|
|
||||||
output.WriteString("\n=== 统计结果 ===\n")
|
|
||||||
output.WriteString(fmt.Sprintf("总环境变量: %d个\n", len(envs)))
|
|
||||||
output.WriteString(fmt.Sprintf("潜在敏感变量: %d个\n", len(sensitiveVars)))
|
|
||||||
|
|
||||||
// 按长度统计
|
|
||||||
shortVars, longVars := 0, 0
|
|
||||||
for _, env := range envs {
|
|
||||||
if len(env) < 50 {
|
|
||||||
shortVars++
|
|
||||||
} else {
|
|
||||||
longVars++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
output.WriteString(fmt.Sprintf("短变量(<50字符): %d个\n", shortVars))
|
|
||||||
output.WriteString(fmt.Sprintf("长变量(≥50字符): %d个\n", longVars))
|
|
||||||
|
|
||||||
return &plugins.Result{
|
|
||||||
Success: len(sensitiveVars) > 0,
|
|
||||||
Output: output.String(),
|
|
||||||
Error: nil,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 注册插件
|
|
||||||
func init() {
|
|
||||||
RegisterLocalPlugin("envinfo", func() Plugin {
|
|
||||||
return NewEnvInfoPlugin()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
+204
-140
@@ -5,6 +5,7 @@ package local
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"os/user"
|
"os/user"
|
||||||
@@ -16,184 +17,247 @@ import (
|
|||||||
"github.com/shadow1ng/fscan/plugins"
|
"github.com/shadow1ng/fscan/plugins"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SystemInfoPlugin 系统信息收集插件
|
|
||||||
// 设计哲学:纯信息收集,无攻击性功能
|
|
||||||
// - 删除复杂的继承体系
|
|
||||||
// - 收集基本系统信息
|
|
||||||
// - 跨平台支持,运行时适配
|
|
||||||
type SystemInfoPlugin struct {
|
type SystemInfoPlugin struct {
|
||||||
plugins.BasePlugin
|
plugins.BasePlugin
|
||||||
|
output strings.Builder
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSystemInfoPlugin 创建系统信息插件
|
|
||||||
func NewSystemInfoPlugin() *SystemInfoPlugin {
|
func NewSystemInfoPlugin() *SystemInfoPlugin {
|
||||||
return &SystemInfoPlugin{
|
return &SystemInfoPlugin{
|
||||||
BasePlugin: plugins.NewBasePlugin("systeminfo"),
|
BasePlugin: plugins.NewBasePlugin("systeminfo"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan 执行系统信息收集 - 直接、简单、有效
|
func (p *SystemInfoPlugin) log(key string, args ...interface{}) {
|
||||||
func (p *SystemInfoPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *plugins.Result {
|
msg := i18n.Tr(key, args...)
|
||||||
var output strings.Builder
|
common.LogInfo(msg)
|
||||||
|
p.output.WriteString(msg + "\n")
|
||||||
|
}
|
||||||
|
|
||||||
output.WriteString("=== 系统信息收集 ===\n")
|
func (p *SystemInfoPlugin) logSuccess(key string, args ...interface{}) {
|
||||||
|
msg := i18n.Tr(key, args...)
|
||||||
|
common.LogSuccess(msg)
|
||||||
|
p.output.WriteString(msg + "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SystemInfoPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *plugins.Result {
|
||||||
common.LogSuccess(i18n.GetText("systeminfo_start"))
|
common.LogSuccess(i18n.GetText("systeminfo_start"))
|
||||||
|
|
||||||
// 基本系统信息
|
p.collectBasicInfo()
|
||||||
output.WriteString(fmt.Sprintf("操作系统: %s\n", runtime.GOOS))
|
p.collectNetworkInfo()
|
||||||
output.WriteString(fmt.Sprintf("架构: %s\n", runtime.GOARCH))
|
p.collectPrivilegeInfo()
|
||||||
output.WriteString(fmt.Sprintf("CPU核心数: %d\n", runtime.NumCPU()))
|
p.collectPlatformInfo()
|
||||||
|
p.collectSensitiveEnvVars()
|
||||||
common.LogInfo(i18n.Tr("systeminfo_os", runtime.GOOS))
|
|
||||||
common.LogInfo(i18n.Tr("systeminfo_arch", runtime.GOARCH))
|
|
||||||
common.LogInfo(i18n.Tr("systeminfo_cpu", runtime.NumCPU()))
|
|
||||||
|
|
||||||
// 主机名
|
|
||||||
if hostname, err := os.Hostname(); err == nil {
|
|
||||||
output.WriteString(fmt.Sprintf("主机名: %s\n", hostname))
|
|
||||||
common.LogInfo(i18n.Tr("systeminfo_hostname", hostname))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 当前用户
|
|
||||||
if currentUser, err := user.Current(); err == nil {
|
|
||||||
output.WriteString(fmt.Sprintf("当前用户: %s\n", currentUser.Username))
|
|
||||||
common.LogInfo(i18n.Tr("systeminfo_user", currentUser.Username))
|
|
||||||
if currentUser.HomeDir != "" {
|
|
||||||
output.WriteString(fmt.Sprintf("用户目录: %s\n", currentUser.HomeDir))
|
|
||||||
common.LogInfo(i18n.Tr("systeminfo_homedir", currentUser.HomeDir))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 工作目录
|
|
||||||
if workDir, err := os.Getwd(); err == nil {
|
|
||||||
output.WriteString(fmt.Sprintf("工作目录: %s\n", workDir))
|
|
||||||
common.LogInfo(i18n.Tr("systeminfo_workdir", workDir))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 临时目录
|
|
||||||
output.WriteString(fmt.Sprintf("临时目录: %s\n", os.TempDir()))
|
|
||||||
common.LogInfo(i18n.Tr("systeminfo_tempdir", os.TempDir()))
|
|
||||||
|
|
||||||
// 环境变量关键信息
|
|
||||||
if path := os.Getenv("PATH"); path != "" {
|
|
||||||
pathCount := len(strings.Split(path, string(os.PathListSeparator)))
|
|
||||||
output.WriteString(fmt.Sprintf("PATH变量条目: %d个\n", pathCount))
|
|
||||||
common.LogInfo(i18n.Tr("systeminfo_pathcount", pathCount))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 平台特定信息
|
|
||||||
platformInfo := p.getPlatformSpecificInfo()
|
|
||||||
if platformInfo != "" {
|
|
||||||
output.WriteString("\n=== 平台特定信息 ===\n")
|
|
||||||
output.WriteString(platformInfo)
|
|
||||||
// 输出平台特定信息到控制台
|
|
||||||
p.logPlatformInfo()
|
|
||||||
}
|
|
||||||
|
|
||||||
return &plugins.Result{
|
return &plugins.Result{
|
||||||
Success: true,
|
Success: true,
|
||||||
Type: plugins.ResultTypeService,
|
Type: plugins.ResultTypeService,
|
||||||
Output: output.String(),
|
Output: p.output.String(),
|
||||||
Error: nil,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// getPlatformSpecificInfo 获取平台特定信息 - 运行时适配,不做预检查
|
func (p *SystemInfoPlugin) collectBasicInfo() {
|
||||||
func (p *SystemInfoPlugin) getPlatformSpecificInfo() string {
|
p.log("systeminfo_os", runtime.GOOS)
|
||||||
var info strings.Builder
|
p.log("systeminfo_arch", runtime.GOARCH)
|
||||||
|
p.log("systeminfo_cpu", runtime.NumCPU())
|
||||||
|
|
||||||
|
if hostname, err := os.Hostname(); err == nil {
|
||||||
|
p.log("systeminfo_hostname", hostname)
|
||||||
|
}
|
||||||
|
if u, err := user.Current(); err == nil {
|
||||||
|
p.log("systeminfo_user", u.Username)
|
||||||
|
if u.HomeDir != "" {
|
||||||
|
p.log("systeminfo_homedir", u.HomeDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if wd, err := os.Getwd(); err == nil {
|
||||||
|
p.log("systeminfo_workdir", wd)
|
||||||
|
}
|
||||||
|
p.log("systeminfo_tempdir", os.TempDir())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SystemInfoPlugin) collectNetworkInfo() {
|
||||||
|
ifaces, err := net.Interfaces()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, iface := range ifaces {
|
||||||
|
if iface.Flags&net.FlagLoopback != 0 || iface.Flags&net.FlagUp == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
addrs, err := iface.Addrs()
|
||||||
|
if err != nil || len(addrs) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var ips []string
|
||||||
|
for _, addr := range addrs {
|
||||||
|
ips = append(ips, addr.String())
|
||||||
|
}
|
||||||
|
p.log("systeminfo_iface", iface.Name, strings.Join(ips, ", "), iface.HardwareAddr.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SystemInfoPlugin) collectPrivilegeInfo() {
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "windows":
|
case "windows":
|
||||||
// Windows版本信息
|
if out, err := p.runCommand("net", "session"); err == nil {
|
||||||
if output, err := p.runCommand("cmd", "/c", "ver"); err == nil {
|
_ = out
|
||||||
info.WriteString(i18n.Tr("systeminfo_winver", strings.TrimSpace(output)) + "\n")
|
p.logSuccess("systeminfo_privilege", "Administrator")
|
||||||
|
} else {
|
||||||
|
p.log("systeminfo_privilege", "Normal User")
|
||||||
}
|
}
|
||||||
|
if out, err := p.runCommand("whoami", "/groups"); err == nil {
|
||||||
// 域信息
|
if strings.Contains(out, "S-1-5-32-544") {
|
||||||
if output, err := p.runCommand("cmd", "/c", "echo %USERDOMAIN%"); err == nil {
|
p.logSuccess("systeminfo_privilege_group", "Administrators")
|
||||||
domain := strings.TrimSpace(output)
|
|
||||||
if domain != "" && domain != "%USERDOMAIN%" {
|
|
||||||
info.WriteString(i18n.Tr("systeminfo_domain", domain) + "\n")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case "linux", "darwin":
|
case "linux", "darwin":
|
||||||
// Unix系统信息
|
if uid := os.Getuid(); uid == 0 {
|
||||||
if output, err := p.runCommand("uname", "-a"); err == nil {
|
p.logSuccess("systeminfo_privilege", "root")
|
||||||
info.WriteString(i18n.Tr("systeminfo_kernel", strings.TrimSpace(output)) + "\n")
|
} else {
|
||||||
|
p.log("systeminfo_privilege", fmt.Sprintf("uid=%d", uid))
|
||||||
}
|
}
|
||||||
|
if out, err := p.runCommand("id"); err == nil {
|
||||||
// 发行版信息(Linux)
|
p.log("systeminfo_id_info", strings.TrimSpace(out))
|
||||||
if runtime.GOOS == "linux" {
|
|
||||||
if output, err := p.runCommand("lsb_release", "-d"); err == nil {
|
|
||||||
info.WriteString(i18n.Tr("systeminfo_distro", strings.TrimSpace(output)) + "\n")
|
|
||||||
} else if p.fileExists("/etc/os-release") {
|
|
||||||
info.WriteString(i18n.GetText("systeminfo_distro_exists") + "\n")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// whoami
|
func (p *SystemInfoPlugin) collectPlatformInfo() {
|
||||||
if output, err := p.runCommand("whoami"); err == nil {
|
switch runtime.GOOS {
|
||||||
info.WriteString(i18n.Tr("systeminfo_whoami", strings.TrimSpace(output)) + "\n")
|
case "windows":
|
||||||
|
p.collectWindowsInfo()
|
||||||
|
case "linux":
|
||||||
|
p.collectLinuxInfo()
|
||||||
|
case "darwin":
|
||||||
|
p.collectDarwinInfo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SystemInfoPlugin) collectWindowsInfo() {
|
||||||
|
if out, err := p.runCommand("cmd", "/c", "ver"); err == nil {
|
||||||
|
p.log("systeminfo_winver", strings.TrimSpace(out))
|
||||||
|
}
|
||||||
|
if out, err := p.runCommand("cmd", "/c", "echo %USERDOMAIN%"); err == nil {
|
||||||
|
domain := strings.TrimSpace(out)
|
||||||
|
if domain != "" && domain != "%USERDOMAIN%" {
|
||||||
|
p.log("systeminfo_domain", domain)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return info.String()
|
// 防火墙状态
|
||||||
|
if out, err := p.runCommand("netsh", "advfirewall", "show", "allprofiles", "state"); err == nil {
|
||||||
|
for _, line := range strings.Split(out, "\n") {
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
if strings.Contains(line, "ON") || strings.Contains(line, "OFF") {
|
||||||
|
p.log("systeminfo_firewall", line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 已安装补丁
|
||||||
|
if out, err := p.runCommand("wmic", "qfe", "get", "HotFixID,InstalledOn"); err == nil {
|
||||||
|
lines := strings.Split(strings.TrimSpace(out), "\n")
|
||||||
|
patches := 0
|
||||||
|
for _, line := range lines {
|
||||||
|
if strings.HasPrefix(strings.TrimSpace(line), "KB") {
|
||||||
|
patches++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if patches > 0 {
|
||||||
|
p.log("systeminfo_patches", patches)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 已安装的杀软 (WMI)
|
||||||
|
if out, err := p.runCommand("wmic", "/namespace:\\\\root\\SecurityCenter2", "path", "AntiVirusProduct", "get", "displayName"); err == nil {
|
||||||
|
for _, line := range strings.Split(out, "\n") {
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
if line != "" && line != "displayName" {
|
||||||
|
p.logSuccess("systeminfo_antivirus", line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SystemInfoPlugin) collectLinuxInfo() {
|
||||||
|
if out, err := p.runCommand("uname", "-a"); err == nil {
|
||||||
|
p.log("systeminfo_kernel", strings.TrimSpace(out))
|
||||||
|
}
|
||||||
|
if data, err := os.ReadFile("/etc/os-release"); err == nil {
|
||||||
|
for _, line := range strings.Split(string(data), "\n") {
|
||||||
|
if strings.HasPrefix(line, "PRETTY_NAME=") {
|
||||||
|
name := strings.Trim(strings.TrimPrefix(line, "PRETTY_NAME="), "\"")
|
||||||
|
p.log("systeminfo_distro", name)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 防火墙
|
||||||
|
if out, err := p.runCommand("iptables", "-L", "-n", "--line-numbers"); err == nil {
|
||||||
|
ruleCount := 0
|
||||||
|
for _, line := range strings.Split(out, "\n") {
|
||||||
|
if len(line) > 0 && line[0] >= '0' && line[0] <= '9' {
|
||||||
|
ruleCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.log("systeminfo_firewall_rules", ruleCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sudo 权限
|
||||||
|
if out, err := p.runCommand("sudo", "-l", "-n"); err == nil {
|
||||||
|
if strings.Contains(out, "ALL") {
|
||||||
|
p.logSuccess("systeminfo_sudo", "ALL commands")
|
||||||
|
} else if strings.Contains(out, "NOPASSWD") {
|
||||||
|
p.logSuccess("systeminfo_sudo", "NOPASSWD entries found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SystemInfoPlugin) collectDarwinInfo() {
|
||||||
|
if out, err := p.runCommand("uname", "-a"); err == nil {
|
||||||
|
p.log("systeminfo_kernel", strings.TrimSpace(out))
|
||||||
|
}
|
||||||
|
if out, err := p.runCommand("sw_vers"); err == nil {
|
||||||
|
for _, line := range strings.Split(out, "\n") {
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
if line != "" {
|
||||||
|
p.log("systeminfo_macos_detail", line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SystemInfoPlugin) collectSensitiveEnvVars() {
|
||||||
|
keywords := []string{
|
||||||
|
"password", "passwd", "secret", "key", "token",
|
||||||
|
"auth", "credential", "api_key", "access_key",
|
||||||
|
}
|
||||||
|
for _, env := range os.Environ() {
|
||||||
|
parts := strings.SplitN(env, "=", 2)
|
||||||
|
if len(parts) != 2 || parts[1] == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
name := strings.ToLower(parts[0])
|
||||||
|
for _, kw := range keywords {
|
||||||
|
if strings.Contains(name, kw) {
|
||||||
|
display := parts[1]
|
||||||
|
if len(display) > 8 {
|
||||||
|
display = display[:8] + "***"
|
||||||
|
}
|
||||||
|
p.logSuccess("systeminfo_sensitive_env", parts[0], display)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// runCommand 执行命令 - 简单包装,无复杂错误处理
|
|
||||||
func (p *SystemInfoPlugin) runCommand(name string, args ...string) (string, error) {
|
func (p *SystemInfoPlugin) runCommand(name string, args ...string) (string, error) {
|
||||||
cmd := exec.Command(name, args...)
|
out, err := exec.Command(name, args...).Output()
|
||||||
output, err := cmd.Output()
|
return string(out), err
|
||||||
return string(output), err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// fileExists 检查文件是否存在
|
|
||||||
func (p *SystemInfoPlugin) fileExists(path string) bool {
|
|
||||||
_, err := os.Stat(path)
|
|
||||||
return err == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// logPlatformInfo 输出平台特定信息到控制台
|
|
||||||
func (p *SystemInfoPlugin) logPlatformInfo() {
|
|
||||||
switch runtime.GOOS {
|
|
||||||
case "windows":
|
|
||||||
// Windows版本信息
|
|
||||||
if output, err := p.runCommand("cmd", "/c", "ver"); err == nil {
|
|
||||||
common.LogInfo(i18n.Tr("systeminfo_winver", strings.TrimSpace(output)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 域信息
|
|
||||||
if output, err := p.runCommand("cmd", "/c", "echo %USERDOMAIN%"); err == nil {
|
|
||||||
domain := strings.TrimSpace(output)
|
|
||||||
if domain != "" && domain != "%USERDOMAIN%" {
|
|
||||||
common.LogInfo(i18n.Tr("systeminfo_domain", domain))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case "linux", "darwin":
|
|
||||||
// Unix系统信息
|
|
||||||
if output, err := p.runCommand("uname", "-a"); err == nil {
|
|
||||||
common.LogInfo(i18n.Tr("systeminfo_kernel", strings.TrimSpace(output)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 发行版信息(Linux)
|
|
||||||
if runtime.GOOS == "linux" {
|
|
||||||
if output, err := p.runCommand("lsb_release", "-d"); err == nil {
|
|
||||||
common.LogInfo(i18n.Tr("systeminfo_distro", strings.TrimSpace(output)))
|
|
||||||
} else if p.fileExists("/etc/os-release") {
|
|
||||||
common.LogInfo(i18n.GetText("systeminfo_distro_exists"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// whoami
|
|
||||||
if output, err := p.runCommand("whoami"); err == nil {
|
|
||||||
common.LogInfo(i18n.Tr("systeminfo_whoami", strings.TrimSpace(output)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 注册插件
|
|
||||||
func init() {
|
func init() {
|
||||||
RegisterLocalPlugin("systeminfo", func() Plugin {
|
RegisterLocalPlugin("systeminfo", func() Plugin {
|
||||||
return NewSystemInfoPlugin()
|
return NewSystemInfoPlugin()
|
||||||
|
|||||||
Reference in New Issue
Block a user