mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-07-13 12:52:44 +08:00
feat: 优化域探测显示,调整Web扫描逻辑
This commit is contained in:
parent
a42ee523b0
commit
75aeee5215
@ -884,6 +884,7 @@ var (
|
|||||||
DisablePing bool // 原NoPing
|
DisablePing bool // 原NoPing
|
||||||
UsePing bool // 原Ping
|
UsePing bool // 原Ping
|
||||||
Command string
|
Command string
|
||||||
|
SkipFingerprint bool
|
||||||
|
|
||||||
// 本地扫描配置
|
// 本地扫描配置
|
||||||
LocalScan bool
|
LocalScan bool
|
||||||
@ -896,8 +897,6 @@ var (
|
|||||||
PortsFile string // 原PortFile
|
PortsFile string // 原PortFile
|
||||||
|
|
||||||
// Web配置
|
// Web配置
|
||||||
TargetURL string // 原URL
|
|
||||||
URLsFile string // 原UrlFile
|
|
||||||
URLs []string // 原Urls
|
URLs []string // 原Urls
|
||||||
WebTimeout int64 = 5
|
WebTimeout int64 = 5
|
||||||
HttpProxy string // 原Proxy
|
HttpProxy string // 原Proxy
|
||||||
@ -906,7 +905,6 @@ var (
|
|||||||
// POC配置
|
// POC配置
|
||||||
PocPath string
|
PocPath string
|
||||||
Pocinfo PocInfo
|
Pocinfo PocInfo
|
||||||
DisablePoc bool // 原NoPoc
|
|
||||||
|
|
||||||
// Redis配置
|
// Redis配置
|
||||||
RedisFile string
|
RedisFile string
|
||||||
|
@ -185,7 +185,6 @@ func Flag(Info *HostInfo) {
|
|||||||
" - Port: 端口扫描模式\n"+
|
" - Port: 端口扫描模式\n"+
|
||||||
" - ICMP: ICMP存活探测\n"+
|
" - ICMP: ICMP存活探测\n"+
|
||||||
" - Local: 本地信息收集\n\n"+
|
" - Local: 本地信息收集\n\n"+
|
||||||
" - UDP: UDP扫描模式\n\n"+
|
|
||||||
"单个插件模式(小写):\n"+
|
"单个插件模式(小写):\n"+
|
||||||
" Web类: web, fcgi\n"+
|
" Web类: web, fcgi\n"+
|
||||||
" 数据库类: mysql, mssql, redis, mongodb, postgres, oracle, memcached\n"+
|
" 数据库类: mysql, mssql, redis, mongodb, postgres, oracle, memcached\n"+
|
||||||
@ -199,9 +198,10 @@ func Flag(Info *HostInfo) {
|
|||||||
flag.BoolVar(&DisablePing, "np", false, "禁用主机存活探测")
|
flag.BoolVar(&DisablePing, "np", false, "禁用主机存活探测")
|
||||||
flag.BoolVar(&UsePing, "ping", false, "使用系统ping命令替代ICMP探测")
|
flag.BoolVar(&UsePing, "ping", false, "使用系统ping命令替代ICMP探测")
|
||||||
flag.StringVar(&Command, "c", "", "指定要执行的系统命令(支持ssh和wmiexec)")
|
flag.StringVar(&Command, "c", "", "指定要执行的系统命令(支持ssh和wmiexec)")
|
||||||
|
flag.BoolVar(&SkipFingerprint, "skip", false, "跳过端口指纹识别")
|
||||||
|
|
||||||
// 本地扫描配置
|
// 本地扫描配置
|
||||||
flag.BoolVar(&LocalScan, "local", false, "启用本地网段扫描模式")
|
flag.BoolVar(&LocalScan, "local", false, "启用本地扫描模式")
|
||||||
|
|
||||||
// 文件配置
|
// 文件配置
|
||||||
flag.StringVar(&HostsFile, "hf", "", "从文件中读取目标主机列表")
|
flag.StringVar(&HostsFile, "hf", "", "从文件中读取目标主机列表")
|
||||||
@ -211,8 +211,6 @@ func Flag(Info *HostInfo) {
|
|||||||
flag.StringVar(&PortsFile, "portf", "", "从文件中读取端口列表")
|
flag.StringVar(&PortsFile, "portf", "", "从文件中读取端口列表")
|
||||||
|
|
||||||
// Web配置
|
// Web配置
|
||||||
flag.StringVar(&TargetURL, "u", "", "指定目标URL")
|
|
||||||
flag.StringVar(&URLsFile, "uf", "", "从文件中读取URL列表")
|
|
||||||
flag.StringVar(&Cookie, "cookie", "", "设置HTTP请求Cookie")
|
flag.StringVar(&Cookie, "cookie", "", "设置HTTP请求Cookie")
|
||||||
flag.Int64Var(&WebTimeout, "wt", 5, "设置Web请求超时时间(单位:秒)")
|
flag.Int64Var(&WebTimeout, "wt", 5, "设置Web请求超时时间(单位:秒)")
|
||||||
flag.StringVar(&HttpProxy, "proxy", "", "设置HTTP代理服务器")
|
flag.StringVar(&HttpProxy, "proxy", "", "设置HTTP代理服务器")
|
||||||
@ -221,7 +219,6 @@ func Flag(Info *HostInfo) {
|
|||||||
// POC配置
|
// POC配置
|
||||||
flag.StringVar(&PocPath, "pocpath", "", "指定自定义POC文件路径")
|
flag.StringVar(&PocPath, "pocpath", "", "指定自定义POC文件路径")
|
||||||
flag.StringVar(&Pocinfo.PocName, "pocname", "", "指定要使用的POC名称,如: -pocname weblogic")
|
flag.StringVar(&Pocinfo.PocName, "pocname", "", "指定要使用的POC名称,如: -pocname weblogic")
|
||||||
flag.BoolVar(&DisablePoc, "nopoc", false, "禁用Web漏洞POC扫描")
|
|
||||||
flag.BoolVar(&PocFull, "full", false, "启用完整POC扫描(如测试shiro全部100个key)")
|
flag.BoolVar(&PocFull, "full", false, "启用完整POC扫描(如测试shiro全部100个key)")
|
||||||
flag.BoolVar(&DnsLog, "dns", false, "启用dnslog进行漏洞验证")
|
flag.BoolVar(&DnsLog, "dns", false, "启用dnslog进行漏洞验证")
|
||||||
flag.IntVar(&PocNum, "num", 20, "设置POC扫描并发数")
|
flag.IntVar(&PocNum, "num", 20, "设置POC扫描并发数")
|
||||||
@ -248,7 +245,7 @@ func Flag(Info *HostInfo) {
|
|||||||
flag.BoolVar(&NoColor, "nocolor", false, "禁用彩色输出显示")
|
flag.BoolVar(&NoColor, "nocolor", false, "禁用彩色输出显示")
|
||||||
flag.BoolVar(&JsonFormat, "json", false, "以JSON格式输出结果")
|
flag.BoolVar(&JsonFormat, "json", false, "以JSON格式输出结果")
|
||||||
flag.StringVar(&LogLevel, "log", LogLevelInfo, "日志输出级别(ALL/SUCCESS/ERROR/INFO/DEBUG)")
|
flag.StringVar(&LogLevel, "log", LogLevelInfo, "日志输出级别(ALL/SUCCESS/ERROR/INFO/DEBUG)")
|
||||||
flag.BoolVar(&NoProgress, "noprogress", false, "禁用进度条显示")
|
flag.BoolVar(&NoProgress, "nopg", false, "禁用进度条显示")
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
}
|
}
|
||||||
|
@ -83,9 +83,17 @@ func formatLogMessage(entry *LogEntry) string {
|
|||||||
|
|
||||||
// 修改 printLog 函数
|
// 修改 printLog 函数
|
||||||
func printLog(entry *LogEntry) {
|
func printLog(entry *LogEntry) {
|
||||||
if LogLevel != LogLevelAll &&
|
// 默认情况(LogLevelInfo)下打印 INFO、SUCCESS、ERROR
|
||||||
entry.Level != LogLevel &&
|
if LogLevel == LogLevelInfo {
|
||||||
!(LogLevel == LogLevelInfo && (entry.Level == LogLevelInfo || entry.Level == LogLevelSuccess)) {
|
if entry.Level != LogLevelInfo &&
|
||||||
|
entry.Level != LogLevelSuccess &&
|
||||||
|
entry.Level != LogLevelError {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else if LogLevel == LogLevelDebug || LogLevel == LogLevelAll {
|
||||||
|
// Debug或ALL模式打印所有日志
|
||||||
|
} else if entry.Level != LogLevel {
|
||||||
|
// 其他情况只打印指定等级的日志
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,40 +114,6 @@ func ParsePass(Info *HostInfo) error {
|
|||||||
LogInfo(fmt.Sprintf("加载有效哈希值: %d 个", validCount))
|
LogInfo(fmt.Sprintf("加载有效哈希值: %d 个", validCount))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理直接指定的URL列表
|
|
||||||
if TargetURL != "" {
|
|
||||||
urls := strings.Split(TargetURL, ",")
|
|
||||||
tmpUrls := make(map[string]struct{})
|
|
||||||
for _, url := range urls {
|
|
||||||
if url != "" {
|
|
||||||
if _, ok := tmpUrls[url]; !ok {
|
|
||||||
tmpUrls[url] = struct{}{}
|
|
||||||
URLs = append(URLs, url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LogInfo(fmt.Sprintf("加载URL: %d 个", len(URLs)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从文件加载URL列表
|
|
||||||
if URLsFile != "" {
|
|
||||||
urls, err := Readfile(URLsFile)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("读取URL文件失败: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
tmpUrls := make(map[string]struct{})
|
|
||||||
for _, url := range urls {
|
|
||||||
if url != "" {
|
|
||||||
if _, ok := tmpUrls[url]; !ok {
|
|
||||||
tmpUrls[url] = struct{}{}
|
|
||||||
URLs = append(URLs, url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LogInfo(fmt.Sprintf("从文件加载URL: %d 个", len(urls)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从文件加载端口列表
|
// 从文件加载端口列表
|
||||||
if PortsFile != "" {
|
if PortsFile != "" {
|
||||||
ports, err := Readfile(PortsFile)
|
ports, err := Readfile(PortsFile)
|
||||||
@ -206,7 +172,7 @@ func Readfile(filename string) ([]string, error) {
|
|||||||
// ParseInput 解析和验证输入参数配置
|
// ParseInput 解析和验证输入参数配置
|
||||||
func ParseInput(Info *HostInfo) error {
|
func ParseInput(Info *HostInfo) error {
|
||||||
// 检查必要的目标参数
|
// 检查必要的目标参数
|
||||||
if Info.Host == "" && HostsFile == "" && TargetURL == "" && URLsFile == "" {
|
if Info.Host == "" && HostsFile == "" {
|
||||||
LogError("未指定扫描目标")
|
LogError("未指定扫描目标")
|
||||||
flag.Usage()
|
flag.Usage()
|
||||||
return fmt.Errorf("必须指定扫描目标")
|
return fmt.Errorf("必须指定扫描目标")
|
||||||
|
@ -18,7 +18,7 @@ const (
|
|||||||
// 插件分类映射表 - 所有插件名使用小写
|
// 插件分类映射表 - 所有插件名使用小写
|
||||||
var pluginGroups = map[string][]string{
|
var pluginGroups = map[string][]string{
|
||||||
ModeAll: {
|
ModeAll: {
|
||||||
"web", "fcgi", // web类
|
"webtitle", "webpoc", "fcgi", // web类
|
||||||
"mysql", "mssql", "redis", "mongodb", "postgres", // 数据库类
|
"mysql", "mssql", "redis", "mongodb", "postgres", // 数据库类
|
||||||
"oracle", "memcached", "elasticsearch", "rabbitmq", "kafka", "activemq", "cassandra", "neo4j", // 数据库类
|
"oracle", "memcached", "elasticsearch", "rabbitmq", "kafka", "activemq", "cassandra", "neo4j", // 数据库类
|
||||||
"ftp", "ssh", "telnet", "smb", "rdp", "vnc", "netbios", "ldap", "smtp", "imap", "pop3", "snmp", "modbus", "rsync", // 服务类
|
"ftp", "ssh", "telnet", "smb", "rdp", "vnc", "netbios", "ldap", "smtp", "imap", "pop3", "snmp", "modbus", "rsync", // 服务类
|
||||||
@ -26,14 +26,14 @@ var pluginGroups = map[string][]string{
|
|||||||
"findnet", // 其他
|
"findnet", // 其他
|
||||||
},
|
},
|
||||||
ModeBasic: {
|
ModeBasic: {
|
||||||
"web", "ftp", "ssh", "smb", "findnet",
|
"webtitle", "ftp", "ssh", "smb", "findnet",
|
||||||
},
|
},
|
||||||
ModeDatabase: {
|
ModeDatabase: {
|
||||||
"mysql", "mssql", "redis", "mongodb",
|
"mysql", "mssql", "redis", "mongodb",
|
||||||
"postgres", "oracle", "memcached", "elasticsearch", "rabbitmq", "kafka", "activemq", "cassandra", "neo4j",
|
"postgres", "oracle", "memcached", "elasticsearch", "rabbitmq", "kafka", "activemq", "cassandra", "neo4j",
|
||||||
},
|
},
|
||||||
ModeWeb: {
|
ModeWeb: {
|
||||||
"web", "fcgi",
|
"webtitle", "webpoc", "fcgi",
|
||||||
},
|
},
|
||||||
ModeService: {
|
ModeService: {
|
||||||
"ftp", "ssh", "telnet", "smb", "rdp", "vnc", "netbios", "ldap", "smtp", "imap", "pop3", "modbus", "rsync",
|
"ftp", "ssh", "telnet", "smb", "rdp", "vnc", "netbios", "ldap", "smtp", "imap", "pop3", "modbus", "rsync",
|
||||||
|
@ -126,27 +126,23 @@ func PortConnect(addr Addr, results chan<- ScanResult, timeout int64, wg *sync.W
|
|||||||
Port: addr.port,
|
Port: addr.port,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 进行服务识别
|
// 只在未跳过指纹识别时进行服务识别
|
||||||
if conn != nil {
|
if !Common.SkipFingerprint && conn != nil {
|
||||||
scanner := NewPortInfoScanner(addr.ip, addr.port, conn, time.Duration(timeout)*time.Second)
|
scanner := NewPortInfoScanner(addr.ip, addr.port, conn, time.Duration(timeout)*time.Second)
|
||||||
if serviceInfo, err := scanner.Identify(); err == nil {
|
if serviceInfo, err := scanner.Identify(); err == nil {
|
||||||
result.Service = serviceInfo
|
result.Service = serviceInfo
|
||||||
|
|
||||||
// 打印服务识别信息
|
|
||||||
var logMsg strings.Builder
|
var logMsg strings.Builder
|
||||||
logMsg.WriteString(fmt.Sprintf("服务识别 %s => ", address))
|
logMsg.WriteString(fmt.Sprintf("服务识别 %s => ", address))
|
||||||
|
|
||||||
// 添加服务名称
|
|
||||||
if serviceInfo.Name != "unknown" {
|
if serviceInfo.Name != "unknown" {
|
||||||
logMsg.WriteString(fmt.Sprintf("[%s]", serviceInfo.Name))
|
logMsg.WriteString(fmt.Sprintf("[%s]", serviceInfo.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加版本信息
|
|
||||||
if serviceInfo.Version != "" {
|
if serviceInfo.Version != "" {
|
||||||
logMsg.WriteString(fmt.Sprintf(" 版本:%s", serviceInfo.Version))
|
logMsg.WriteString(fmt.Sprintf(" 版本:%s", serviceInfo.Version))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加其他有用的信息
|
|
||||||
if v, ok := serviceInfo.Extras["vendor_product"]; ok && v != "" {
|
if v, ok := serviceInfo.Extras["vendor_product"]; ok && v != "" {
|
||||||
logMsg.WriteString(fmt.Sprintf(" 产品:%s", v))
|
logMsg.WriteString(fmt.Sprintf(" 产品:%s", v))
|
||||||
}
|
}
|
||||||
@ -157,7 +153,6 @@ func PortConnect(addr Addr, results chan<- ScanResult, timeout int64, wg *sync.W
|
|||||||
logMsg.WriteString(fmt.Sprintf(" 信息:%s", v))
|
logMsg.WriteString(fmt.Sprintf(" 信息:%s", v))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果有Banner且长度合适,也输出
|
|
||||||
if len(serviceInfo.Banner) > 0 && len(serviceInfo.Banner) < 100 {
|
if len(serviceInfo.Banner) > 0 && len(serviceInfo.Banner) < 100 {
|
||||||
logMsg.WriteString(fmt.Sprintf(" Banner:[%s]", strings.TrimSpace(serviceInfo.Banner)))
|
logMsg.WriteString(fmt.Sprintf(" Banner:[%s]", strings.TrimSpace(serviceInfo.Banner)))
|
||||||
}
|
}
|
||||||
@ -166,7 +161,6 @@ func PortConnect(addr Addr, results chan<- ScanResult, timeout int64, wg *sync.W
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 发送结果
|
|
||||||
results <- result
|
results <- result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,7 +195,7 @@ func init() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// web 相关插件添加 WebPorts 配置
|
// web 相关插件添加 WebPorts 配置
|
||||||
Common.RegisterPlugin("web", Common.ScanPlugin{
|
Common.RegisterPlugin("webtitle", Common.ScanPlugin{
|
||||||
Name: "WebTitle",
|
Name: "WebTitle",
|
||||||
Ports: Common.ParsePortsFromString(Common.WebPorts), // 将 WebPorts 字符串解析为端口数组
|
Ports: Common.ParsePortsFromString(Common.WebPorts), // 将 WebPorts 字符串解析为端口数组
|
||||||
ScanFunc: Plugins.WebTitle,
|
ScanFunc: Plugins.WebTitle,
|
||||||
|
@ -222,16 +222,18 @@ func executeScans(targets []Common.HostInfo, ch *chan struct{}, wg *sync.WaitGro
|
|||||||
// finishScan 完成扫描任务
|
// finishScan 完成扫描任务
|
||||||
func finishScan(wg *sync.WaitGroup) {
|
func finishScan(wg *sync.WaitGroup) {
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
// 确保进度条完成
|
// 确保进度条完成,只在存在进度条时调用
|
||||||
|
if Common.ProgressBar != nil {
|
||||||
Common.ProgressBar.Finish()
|
Common.ProgressBar.Finish()
|
||||||
fmt.Println() // 添加一个换行
|
fmt.Println() // 添加一个换行
|
||||||
|
}
|
||||||
Common.LogSuccess(fmt.Sprintf("扫描已完成: %v/%v", Common.End, Common.Num))
|
Common.LogSuccess(fmt.Sprintf("扫描已完成: %v/%v", Common.End, Common.Num))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mutex用于保护共享资源的并发访问
|
// Mutex用于保护共享资源的并发访问
|
||||||
var Mutex = &sync.Mutex{}
|
var Mutex = &sync.Mutex{}
|
||||||
|
|
||||||
// AddScan 也需要修改
|
// AddScan
|
||||||
func AddScan(plugin string, info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
func AddScan(plugin string, info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||||
*ch <- struct{}{}
|
*ch <- struct{}{}
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
|
@ -4,16 +4,12 @@ package Plugins
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/go-ldap/ldap/v3"
|
||||||
"github.com/go-ldap/ldap/v3/gssapi"
|
"github.com/go-ldap/ldap/v3/gssapi"
|
||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
"log"
|
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/go-ldap/ldap/v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type DomainInfo struct {
|
type DomainInfo struct {
|
||||||
@ -28,7 +24,8 @@ func (d *DomainInfo) Close() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *DomainInfo) GetCAComputers() ([]string, error) {
|
func (d *DomainInfo) GetCAComputers() ([]string, error) {
|
||||||
// 在Configuration容器中查找CA服务器
|
Common.LogDebug("开始查询域内CA服务器...")
|
||||||
|
|
||||||
searchRequest := ldap.NewSearchRequest(
|
searchRequest := ldap.NewSearchRequest(
|
||||||
"CN=Configuration,"+d.baseDN,
|
"CN=Configuration,"+d.baseDN,
|
||||||
ldap.ScopeWholeSubtree,
|
ldap.ScopeWholeSubtree,
|
||||||
@ -36,13 +33,14 @@ func (d *DomainInfo) GetCAComputers() ([]string, error) {
|
|||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
false,
|
false,
|
||||||
"(&(objectCategory=pKIEnrollmentService))", // CA服务器的查询条件
|
"(&(objectCategory=pKIEnrollmentService))",
|
||||||
[]string{"cn", "dNSHostName"},
|
[]string{"cn", "dNSHostName"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
|
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Common.LogError(fmt.Sprintf("查询CA服务器失败: %v", err))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,12 +49,22 @@ func (d *DomainInfo) GetCAComputers() ([]string, error) {
|
|||||||
cn := entry.GetAttributeValue("cn")
|
cn := entry.GetAttributeValue("cn")
|
||||||
if cn != "" {
|
if cn != "" {
|
||||||
caComputers = append(caComputers, cn)
|
caComputers = append(caComputers, cn)
|
||||||
|
Common.LogDebug(fmt.Sprintf("发现CA服务器: %s", cn))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(caComputers) > 0 {
|
||||||
|
Common.LogSuccess(fmt.Sprintf("共发现 %d 个CA服务器", len(caComputers)))
|
||||||
|
} else {
|
||||||
|
Common.LogDebug("未发现CA服务器")
|
||||||
|
}
|
||||||
|
|
||||||
return caComputers, nil
|
return caComputers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DomainInfo) GetExchangeServers() ([]string, error) {
|
func (d *DomainInfo) GetExchangeServers() ([]string, error) {
|
||||||
|
Common.LogDebug("开始查询Exchange服务器...")
|
||||||
|
|
||||||
searchRequest := ldap.NewSearchRequest(
|
searchRequest := ldap.NewSearchRequest(
|
||||||
d.baseDN,
|
d.baseDN,
|
||||||
ldap.ScopeWholeSubtree,
|
ldap.ScopeWholeSubtree,
|
||||||
@ -71,6 +79,7 @@ func (d *DomainInfo) GetExchangeServers() ([]string, error) {
|
|||||||
|
|
||||||
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
|
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Common.LogError(fmt.Sprintf("查询Exchange服务器失败: %v", err))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,6 +88,7 @@ func (d *DomainInfo) GetExchangeServers() ([]string, error) {
|
|||||||
for _, member := range entry.GetAttributeValues("member") {
|
for _, member := range entry.GetAttributeValues("member") {
|
||||||
if member != "" {
|
if member != "" {
|
||||||
exchangeServers = append(exchangeServers, member)
|
exchangeServers = append(exchangeServers, member)
|
||||||
|
Common.LogDebug(fmt.Sprintf("发现Exchange服务器成员: %s", member))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,12 +96,21 @@ func (d *DomainInfo) GetExchangeServers() ([]string, error) {
|
|||||||
// 移除第一个条目(如果存在)
|
// 移除第一个条目(如果存在)
|
||||||
if len(exchangeServers) > 1 {
|
if len(exchangeServers) > 1 {
|
||||||
exchangeServers = exchangeServers[1:]
|
exchangeServers = exchangeServers[1:]
|
||||||
|
Common.LogDebug("移除第一个条目")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(exchangeServers) > 0 {
|
||||||
|
Common.LogSuccess(fmt.Sprintf("共发现 %d 个Exchange服务器", len(exchangeServers)))
|
||||||
|
} else {
|
||||||
|
Common.LogDebug("未发现Exchange服务器")
|
||||||
}
|
}
|
||||||
|
|
||||||
return exchangeServers, nil
|
return exchangeServers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DomainInfo) GetMsSqlServers() ([]string, error) {
|
func (d *DomainInfo) GetMsSqlServers() ([]string, error) {
|
||||||
|
Common.LogDebug("开始查询SQL Server服务器...")
|
||||||
|
|
||||||
searchRequest := ldap.NewSearchRequest(
|
searchRequest := ldap.NewSearchRequest(
|
||||||
d.baseDN,
|
d.baseDN,
|
||||||
ldap.ScopeWholeSubtree,
|
ldap.ScopeWholeSubtree,
|
||||||
@ -106,6 +125,7 @@ func (d *DomainInfo) GetMsSqlServers() ([]string, error) {
|
|||||||
|
|
||||||
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
|
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Common.LogError(fmt.Sprintf("查询SQL Server失败: %v", err))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,28 +134,43 @@ func (d *DomainInfo) GetMsSqlServers() ([]string, error) {
|
|||||||
name := entry.GetAttributeValue("name")
|
name := entry.GetAttributeValue("name")
|
||||||
if name != "" {
|
if name != "" {
|
||||||
sqlServers = append(sqlServers, name)
|
sqlServers = append(sqlServers, name)
|
||||||
|
Common.LogDebug(fmt.Sprintf("发现SQL Server: %s", name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(sqlServers) > 0 {
|
||||||
|
Common.LogSuccess(fmt.Sprintf("共发现 %d 个SQL Server", len(sqlServers)))
|
||||||
|
} else {
|
||||||
|
Common.LogDebug("未发现SQL Server")
|
||||||
|
}
|
||||||
|
|
||||||
return sqlServers, nil
|
return sqlServers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DomainInfo) GetSpecialComputers() (map[string][]string, error) {
|
func (d *DomainInfo) GetSpecialComputers() (map[string][]string, error) {
|
||||||
|
Common.LogDebug("开始查询特殊计算机...")
|
||||||
results := make(map[string][]string)
|
results := make(map[string][]string)
|
||||||
|
|
||||||
// 获取SQL Server
|
// 获取SQL Server
|
||||||
|
Common.LogDebug("正在查询SQL Server...")
|
||||||
sqlServers, err := d.GetMsSqlServers()
|
sqlServers, err := d.GetMsSqlServers()
|
||||||
if err == nil && len(sqlServers) > 0 {
|
if err == nil && len(sqlServers) > 0 {
|
||||||
results["SQL服务器"] = sqlServers
|
results["SQL服务器"] = sqlServers
|
||||||
|
} else if err != nil {
|
||||||
|
Common.LogError(fmt.Sprintf("查询SQL Server时出错: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取CA服务器
|
// 获取CA服务器
|
||||||
|
Common.LogDebug("正在查询CA服务器...")
|
||||||
caComputers, err := d.GetCAComputers()
|
caComputers, err := d.GetCAComputers()
|
||||||
if err == nil && len(caComputers) > 0 {
|
if err == nil && len(caComputers) > 0 {
|
||||||
results["CA服务器"] = caComputers
|
results["CA服务器"] = caComputers
|
||||||
|
} else if err != nil {
|
||||||
|
Common.LogError(fmt.Sprintf("查询CA服务器时出错: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取域控制器
|
// 获取域控制器
|
||||||
|
Common.LogDebug("正在查询域控制器...")
|
||||||
dcQuery := ldap.NewSearchRequest(
|
dcQuery := ldap.NewSearchRequest(
|
||||||
d.baseDN,
|
d.baseDN,
|
||||||
ldap.ScopeWholeSubtree,
|
ldap.ScopeWholeSubtree,
|
||||||
@ -154,24 +189,42 @@ func (d *DomainInfo) GetSpecialComputers() (map[string][]string, error) {
|
|||||||
name := entry.GetAttributeValue("cn")
|
name := entry.GetAttributeValue("cn")
|
||||||
if name != "" {
|
if name != "" {
|
||||||
dcs = append(dcs, name)
|
dcs = append(dcs, name)
|
||||||
|
Common.LogDebug(fmt.Sprintf("发现域控制器: %s", name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(dcs) > 0 {
|
if len(dcs) > 0 {
|
||||||
results["域控制器"] = dcs
|
results["域控制器"] = dcs
|
||||||
|
Common.LogSuccess(fmt.Sprintf("共发现 %d 个域控制器", len(dcs)))
|
||||||
|
} else {
|
||||||
|
Common.LogDebug("未发现域控制器")
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Common.LogError(fmt.Sprintf("查询域控制器时出错: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取Exchange服务器
|
// 获取Exchange服务器
|
||||||
|
Common.LogDebug("正在查询Exchange服务器...")
|
||||||
exchangeServers, err := d.GetExchangeServers()
|
exchangeServers, err := d.GetExchangeServers()
|
||||||
if err == nil && len(exchangeServers) > 0 {
|
if err == nil && len(exchangeServers) > 0 {
|
||||||
results["Exchange服务器"] = exchangeServers
|
results["Exchange服务器"] = exchangeServers
|
||||||
|
} else if err != nil {
|
||||||
|
Common.LogError(fmt.Sprintf("查询Exchange服务器时出错: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(results) > 0 {
|
||||||
|
Common.LogSuccess(fmt.Sprintf("特殊计算机查询完成,共发现 %d 类服务器", len(results)))
|
||||||
|
for serverType, servers := range results {
|
||||||
|
Common.LogDebug(fmt.Sprintf("%s: %d 台", serverType, len(servers)))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Common.LogDebug("未发现任何特殊计算机")
|
||||||
}
|
}
|
||||||
|
|
||||||
return results, nil
|
return results, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取域用户
|
|
||||||
func (d *DomainInfo) GetDomainUsers() ([]string, error) {
|
func (d *DomainInfo) GetDomainUsers() ([]string, error) {
|
||||||
|
Common.LogDebug("开始查询域用户...")
|
||||||
|
|
||||||
searchRequest := ldap.NewSearchRequest(
|
searchRequest := ldap.NewSearchRequest(
|
||||||
d.baseDN,
|
d.baseDN,
|
||||||
@ -187,19 +240,31 @@ func (d *DomainInfo) GetDomainUsers() ([]string, error) {
|
|||||||
|
|
||||||
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
|
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Common.LogError(fmt.Sprintf("查询域用户失败: %v", err))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var users []string
|
var users []string
|
||||||
for _, entry := range sr.Entries {
|
for _, entry := range sr.Entries {
|
||||||
users = append(users, entry.GetAttributeValue("sAMAccountName"))
|
username := entry.GetAttributeValue("sAMAccountName")
|
||||||
|
if username != "" {
|
||||||
|
users = append(users, username)
|
||||||
|
Common.LogDebug(fmt.Sprintf("发现用户: %s", username))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(users) > 0 {
|
||||||
|
Common.LogSuccess(fmt.Sprintf("共发现 %d 个域用户", len(users)))
|
||||||
|
} else {
|
||||||
|
Common.LogDebug("未发现域用户")
|
||||||
}
|
}
|
||||||
|
|
||||||
return users, nil
|
return users, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取域管理员
|
|
||||||
func (d *DomainInfo) GetDomainAdmins() ([]string, error) {
|
func (d *DomainInfo) GetDomainAdmins() ([]string, error) {
|
||||||
|
Common.LogDebug("开始查询域管理员...")
|
||||||
|
|
||||||
searchRequest := ldap.NewSearchRequest(
|
searchRequest := ldap.NewSearchRequest(
|
||||||
d.baseDN,
|
d.baseDN,
|
||||||
ldap.ScopeWholeSubtree,
|
ldap.ScopeWholeSubtree,
|
||||||
@ -214,15 +279,15 @@ func (d *DomainInfo) GetDomainAdmins() ([]string, error) {
|
|||||||
|
|
||||||
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
|
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Common.LogError(fmt.Sprintf("查询Domain Admins组失败: %v", err))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var admins []string
|
var admins []string
|
||||||
if len(sr.Entries) > 0 {
|
if len(sr.Entries) > 0 {
|
||||||
// 获取组成员
|
|
||||||
members := sr.Entries[0].GetAttributeValues("member")
|
members := sr.Entries[0].GetAttributeValues("member")
|
||||||
|
Common.LogDebug(fmt.Sprintf("发现 %d 个Domain Admins组成员", len(members)))
|
||||||
|
|
||||||
// 对每个成员DN执行查询以获取其sAMAccountName
|
|
||||||
for _, memberDN := range members {
|
for _, memberDN := range members {
|
||||||
memberSearch := ldap.NewSearchRequest(
|
memberSearch := ldap.NewSearchRequest(
|
||||||
memberDN,
|
memberDN,
|
||||||
@ -238,23 +303,32 @@ func (d *DomainInfo) GetDomainAdmins() ([]string, error) {
|
|||||||
|
|
||||||
memberResult, err := d.conn.Search(memberSearch)
|
memberResult, err := d.conn.Search(memberSearch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue // 跳过出错的成员
|
Common.LogError(fmt.Sprintf("查询成员 %s 失败: %v", memberDN, err))
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(memberResult.Entries) > 0 {
|
if len(memberResult.Entries) > 0 {
|
||||||
samAccountName := memberResult.Entries[0].GetAttributeValue("sAMAccountName")
|
samAccountName := memberResult.Entries[0].GetAttributeValue("sAMAccountName")
|
||||||
if samAccountName != "" {
|
if samAccountName != "" {
|
||||||
admins = append(admins, samAccountName)
|
admins = append(admins, samAccountName)
|
||||||
|
Common.LogDebug(fmt.Sprintf("发现域管理员: %s", samAccountName))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(admins) > 0 {
|
||||||
|
Common.LogSuccess(fmt.Sprintf("共发现 %d 个域管理员", len(admins)))
|
||||||
|
} else {
|
||||||
|
Common.LogDebug("未发现域管理员")
|
||||||
|
}
|
||||||
|
|
||||||
return admins, nil
|
return admins, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取组织单位(OU)
|
|
||||||
func (d *DomainInfo) GetOUs() ([]string, error) {
|
func (d *DomainInfo) GetOUs() ([]string, error) {
|
||||||
|
Common.LogDebug("开始查询组织单位(OU)...")
|
||||||
|
|
||||||
searchRequest := ldap.NewSearchRequest(
|
searchRequest := ldap.NewSearchRequest(
|
||||||
d.baseDN,
|
d.baseDN,
|
||||||
ldap.ScopeWholeSubtree,
|
ldap.ScopeWholeSubtree,
|
||||||
@ -269,6 +343,7 @@ func (d *DomainInfo) GetOUs() ([]string, error) {
|
|||||||
|
|
||||||
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
|
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Common.LogError(fmt.Sprintf("查询OU失败: %v", err))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,12 +352,22 @@ func (d *DomainInfo) GetOUs() ([]string, error) {
|
|||||||
ou := entry.GetAttributeValue("ou")
|
ou := entry.GetAttributeValue("ou")
|
||||||
if ou != "" {
|
if ou != "" {
|
||||||
ous = append(ous, ou)
|
ous = append(ous, ou)
|
||||||
|
Common.LogDebug(fmt.Sprintf("发现OU: %s", ou))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(ous) > 0 {
|
||||||
|
Common.LogSuccess(fmt.Sprintf("共发现 %d 个组织单位", len(ous)))
|
||||||
|
} else {
|
||||||
|
Common.LogDebug("未发现组织单位")
|
||||||
|
}
|
||||||
|
|
||||||
return ous, nil
|
return ous, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DomainInfo) GetComputers() ([]Computer, error) {
|
func (d *DomainInfo) GetComputers() ([]Computer, error) {
|
||||||
|
Common.LogDebug("开始查询域内计算机...")
|
||||||
|
|
||||||
searchRequest := ldap.NewSearchRequest(
|
searchRequest := ldap.NewSearchRequest(
|
||||||
d.baseDN,
|
d.baseDN,
|
||||||
ldap.ScopeWholeSubtree,
|
ldap.ScopeWholeSubtree,
|
||||||
@ -297,6 +382,7 @@ func (d *DomainInfo) GetComputers() ([]Computer, error) {
|
|||||||
|
|
||||||
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
|
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Common.LogError(fmt.Sprintf("查询计算机失败: %v", err))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,7 +394,30 @@ func (d *DomainInfo) GetComputers() ([]Computer, error) {
|
|||||||
DNSHostName: entry.GetAttributeValue("dNSHostName"),
|
DNSHostName: entry.GetAttributeValue("dNSHostName"),
|
||||||
}
|
}
|
||||||
computers = append(computers, computer)
|
computers = append(computers, computer)
|
||||||
|
Common.LogDebug(fmt.Sprintf("发现计算机: %s (OS: %s, DNS: %s)",
|
||||||
|
computer.Name,
|
||||||
|
computer.OperatingSystem,
|
||||||
|
computer.DNSHostName))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(computers) > 0 {
|
||||||
|
Common.LogSuccess(fmt.Sprintf("共发现 %d 台计算机", len(computers)))
|
||||||
|
|
||||||
|
// 统计操作系统分布
|
||||||
|
osCount := make(map[string]int)
|
||||||
|
for _, computer := range computers {
|
||||||
|
if computer.OperatingSystem != "" {
|
||||||
|
osCount[computer.OperatingSystem]++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for os, count := range osCount {
|
||||||
|
Common.LogDebug(fmt.Sprintf("操作系统 %s: %d 台", os, count))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Common.LogDebug("未发现计算机")
|
||||||
|
}
|
||||||
|
|
||||||
return computers, nil
|
return computers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,8 +428,9 @@ type Computer struct {
|
|||||||
DNSHostName string
|
DNSHostName string
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取信任域关系
|
|
||||||
func (d *DomainInfo) GetTrustDomains() ([]string, error) {
|
func (d *DomainInfo) GetTrustDomains() ([]string, error) {
|
||||||
|
Common.LogDebug("开始查询域信任关系...")
|
||||||
|
|
||||||
searchRequest := ldap.NewSearchRequest(
|
searchRequest := ldap.NewSearchRequest(
|
||||||
d.baseDN,
|
d.baseDN,
|
||||||
ldap.ScopeWholeSubtree,
|
ldap.ScopeWholeSubtree,
|
||||||
@ -335,6 +445,7 @@ func (d *DomainInfo) GetTrustDomains() ([]string, error) {
|
|||||||
|
|
||||||
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
|
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Common.LogError(fmt.Sprintf("查询信任域失败: %v", err))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,13 +454,22 @@ func (d *DomainInfo) GetTrustDomains() ([]string, error) {
|
|||||||
cn := entry.GetAttributeValue("cn")
|
cn := entry.GetAttributeValue("cn")
|
||||||
if cn != "" {
|
if cn != "" {
|
||||||
trustInfo = append(trustInfo, cn)
|
trustInfo = append(trustInfo, cn)
|
||||||
|
Common.LogDebug(fmt.Sprintf("发现信任域: %s", cn))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(trustInfo) > 0 {
|
||||||
|
Common.LogSuccess(fmt.Sprintf("共发现 %d 个信任域", len(trustInfo)))
|
||||||
|
} else {
|
||||||
|
Common.LogDebug("未发现信任域关系")
|
||||||
|
}
|
||||||
|
|
||||||
return trustInfo, nil
|
return trustInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取域管理员组成员
|
|
||||||
func (d *DomainInfo) GetAdminGroups() (map[string][]string, error) {
|
func (d *DomainInfo) GetAdminGroups() (map[string][]string, error) {
|
||||||
|
Common.LogDebug("开始查询管理员组信息...")
|
||||||
|
|
||||||
adminGroups := map[string]string{
|
adminGroups := map[string]string{
|
||||||
"Domain Admins": "(&(objectClass=group)(cn=Domain Admins))",
|
"Domain Admins": "(&(objectClass=group)(cn=Domain Admins))",
|
||||||
"Enterprise Admins": "(&(objectClass=group)(cn=Enterprise Admins))",
|
"Enterprise Admins": "(&(objectClass=group)(cn=Enterprise Admins))",
|
||||||
@ -359,6 +479,8 @@ func (d *DomainInfo) GetAdminGroups() (map[string][]string, error) {
|
|||||||
results := make(map[string][]string)
|
results := make(map[string][]string)
|
||||||
|
|
||||||
for groupName, filter := range adminGroups {
|
for groupName, filter := range adminGroups {
|
||||||
|
Common.LogDebug(fmt.Sprintf("正在查询 %s 组...", groupName))
|
||||||
|
|
||||||
searchRequest := ldap.NewSearchRequest(
|
searchRequest := ldap.NewSearchRequest(
|
||||||
d.baseDN,
|
d.baseDN,
|
||||||
ldap.ScopeWholeSubtree,
|
ldap.ScopeWholeSubtree,
|
||||||
@ -373,6 +495,7 @@ func (d *DomainInfo) GetAdminGroups() (map[string][]string, error) {
|
|||||||
|
|
||||||
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
|
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Common.LogError(fmt.Sprintf("查询 %s 组失败: %v", groupName, err))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,14 +503,28 @@ func (d *DomainInfo) GetAdminGroups() (map[string][]string, error) {
|
|||||||
members := sr.Entries[0].GetAttributeValues("member")
|
members := sr.Entries[0].GetAttributeValues("member")
|
||||||
if len(members) > 0 {
|
if len(members) > 0 {
|
||||||
results[groupName] = members
|
results[groupName] = members
|
||||||
|
Common.LogDebug(fmt.Sprintf("%s 组成员数量: %d", groupName, len(members)))
|
||||||
|
for _, member := range members {
|
||||||
|
Common.LogDebug(fmt.Sprintf("- %s: %s", groupName, member))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Common.LogDebug(fmt.Sprintf("%s 组未发现成员", groupName))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(results) > 0 {
|
||||||
|
Common.LogSuccess(fmt.Sprintf("共发现 %d 个管理员组", len(results)))
|
||||||
|
} else {
|
||||||
|
Common.LogDebug("未发现管理员组信息")
|
||||||
|
}
|
||||||
|
|
||||||
return results, nil
|
return results, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取委派信息
|
|
||||||
func (d *DomainInfo) GetDelegation() (map[string][]string, error) {
|
func (d *DomainInfo) GetDelegation() (map[string][]string, error) {
|
||||||
|
Common.LogDebug("开始查询委派信息...")
|
||||||
|
|
||||||
delegationQueries := map[string]string{
|
delegationQueries := map[string]string{
|
||||||
"非约束委派": "(&(objectCategory=computer)(userAccountControl:1.2.840.113556.1.4.803:=524288))",
|
"非约束委派": "(&(objectCategory=computer)(userAccountControl:1.2.840.113556.1.4.803:=524288))",
|
||||||
"约束委派": "(msDS-AllowedToDelegateTo=*)",
|
"约束委派": "(msDS-AllowedToDelegateTo=*)",
|
||||||
@ -397,6 +534,8 @@ func (d *DomainInfo) GetDelegation() (map[string][]string, error) {
|
|||||||
results := make(map[string][]string)
|
results := make(map[string][]string)
|
||||||
|
|
||||||
for delegationType, query := range delegationQueries {
|
for delegationType, query := range delegationQueries {
|
||||||
|
Common.LogDebug(fmt.Sprintf("正在查询%s...", delegationType))
|
||||||
|
|
||||||
searchRequest := ldap.NewSearchRequest(
|
searchRequest := ldap.NewSearchRequest(
|
||||||
d.baseDN,
|
d.baseDN,
|
||||||
ldap.ScopeWholeSubtree,
|
ldap.ScopeWholeSubtree,
|
||||||
@ -411,6 +550,7 @@ func (d *DomainInfo) GetDelegation() (map[string][]string, error) {
|
|||||||
|
|
||||||
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
|
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Common.LogError(fmt.Sprintf("查询%s失败: %v", delegationType, err))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,18 +559,31 @@ func (d *DomainInfo) GetDelegation() (map[string][]string, error) {
|
|||||||
cn := entry.GetAttributeValue("cn")
|
cn := entry.GetAttributeValue("cn")
|
||||||
if cn != "" {
|
if cn != "" {
|
||||||
entries = append(entries, cn)
|
entries = append(entries, cn)
|
||||||
|
Common.LogDebug(fmt.Sprintf("发现%s: %s", delegationType, cn))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(entries) > 0 {
|
if len(entries) > 0 {
|
||||||
results[delegationType] = entries
|
results[delegationType] = entries
|
||||||
|
Common.LogSuccess(fmt.Sprintf("%s: 发现 %d 条记录", delegationType, len(entries)))
|
||||||
|
} else {
|
||||||
|
Common.LogDebug(fmt.Sprintf("未发现%s记录", delegationType))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(results) > 0 {
|
||||||
|
Common.LogSuccess(fmt.Sprintf("共发现 %d 类委派配置", len(results)))
|
||||||
|
} else {
|
||||||
|
Common.LogDebug("未发现任何委派配置")
|
||||||
|
}
|
||||||
|
|
||||||
return results, nil
|
return results, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取AS-REP Roasting漏洞用户
|
// 获取AS-REP Roasting漏洞用户
|
||||||
func (d *DomainInfo) GetAsrepRoastUsers() ([]string, error) {
|
func (d *DomainInfo) GetAsrepRoastUsers() ([]string, error) {
|
||||||
|
Common.LogDebug("开始查询AS-REP Roasting漏洞用户...")
|
||||||
|
|
||||||
searchRequest := ldap.NewSearchRequest(
|
searchRequest := ldap.NewSearchRequest(
|
||||||
d.baseDN,
|
d.baseDN,
|
||||||
ldap.ScopeWholeSubtree,
|
ldap.ScopeWholeSubtree,
|
||||||
@ -445,6 +598,7 @@ func (d *DomainInfo) GetAsrepRoastUsers() ([]string, error) {
|
|||||||
|
|
||||||
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
|
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Common.LogError(fmt.Sprintf("查询AS-REP Roasting漏洞用户失败: %v", err))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -453,13 +607,22 @@ func (d *DomainInfo) GetAsrepRoastUsers() ([]string, error) {
|
|||||||
name := entry.GetAttributeValue("sAMAccountName")
|
name := entry.GetAttributeValue("sAMAccountName")
|
||||||
if name != "" {
|
if name != "" {
|
||||||
users = append(users, name)
|
users = append(users, name)
|
||||||
|
Common.LogDebug(fmt.Sprintf("发现存在AS-REP Roasting漏洞的用户: %s", name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(users) > 0 {
|
||||||
|
Common.LogSuccess(fmt.Sprintf("共发现 %d 个存在AS-REP Roasting漏洞的用户", len(users)))
|
||||||
|
} else {
|
||||||
|
Common.LogDebug("未发现存在AS-REP Roasting漏洞的用户")
|
||||||
|
}
|
||||||
|
|
||||||
return users, nil
|
return users, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取域密码策略
|
|
||||||
func (d *DomainInfo) GetPasswordPolicy() (map[string]string, error) {
|
func (d *DomainInfo) GetPasswordPolicy() (map[string]string, error) {
|
||||||
|
Common.LogDebug("开始查询域密码策略...")
|
||||||
|
|
||||||
searchRequest := ldap.NewSearchRequest(
|
searchRequest := ldap.NewSearchRequest(
|
||||||
d.baseDN,
|
d.baseDN,
|
||||||
ldap.ScopeBaseObject,
|
ldap.ScopeBaseObject,
|
||||||
@ -482,42 +645,66 @@ func (d *DomainInfo) GetPasswordPolicy() (map[string]string, error) {
|
|||||||
|
|
||||||
sr, err := d.conn.Search(searchRequest)
|
sr, err := d.conn.Search(searchRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Common.LogError(fmt.Sprintf("查询密码策略失败: %v", err))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(sr.Entries) == 0 {
|
if len(sr.Entries) == 0 {
|
||||||
|
Common.LogError("未找到密码策略信息")
|
||||||
return nil, fmt.Errorf("未找到密码策略信息")
|
return nil, fmt.Errorf("未找到密码策略信息")
|
||||||
}
|
}
|
||||||
|
|
||||||
policy := make(map[string]string)
|
policy := make(map[string]string)
|
||||||
entry := sr.Entries[0]
|
entry := sr.Entries[0]
|
||||||
|
|
||||||
// 转换最大密码期限(负值,以100纳秒为单位)
|
// 转换最大密码期限
|
||||||
if maxAge := entry.GetAttributeValue("maxPwdAge"); maxAge != "" {
|
if maxAge := entry.GetAttributeValue("maxPwdAge"); maxAge != "" {
|
||||||
maxAgeInt, _ := strconv.ParseInt(maxAge, 10, 64)
|
maxAgeInt, _ := strconv.ParseInt(maxAge, 10, 64)
|
||||||
if maxAgeInt != 0 {
|
if maxAgeInt != 0 {
|
||||||
days := float64(maxAgeInt) * -1 / float64(864000000000)
|
days := float64(maxAgeInt) * -1 / float64(864000000000)
|
||||||
policy["最大密码期限"] = fmt.Sprintf("%.0f天", days)
|
policy["最大密码期限"] = fmt.Sprintf("%.0f天", days)
|
||||||
|
Common.LogDebug(fmt.Sprintf("最大密码期限: %.0f天", days))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if minLength := entry.GetAttributeValue("minPwdLength"); minLength != "" {
|
if minLength := entry.GetAttributeValue("minPwdLength"); minLength != "" {
|
||||||
policy["最小密码长度"] = minLength + "个字符"
|
policy["最小密码长度"] = minLength + "个字符"
|
||||||
|
Common.LogDebug(fmt.Sprintf("最小密码长度: %s个字符", minLength))
|
||||||
}
|
}
|
||||||
|
|
||||||
if historyLength := entry.GetAttributeValue("pwdHistoryLength"); historyLength != "" {
|
if historyLength := entry.GetAttributeValue("pwdHistoryLength"); historyLength != "" {
|
||||||
policy["密码历史长度"] = historyLength + "个"
|
policy["密码历史长度"] = historyLength + "个"
|
||||||
|
Common.LogDebug(fmt.Sprintf("密码历史长度: %s个", historyLength))
|
||||||
}
|
}
|
||||||
|
|
||||||
if lockoutThreshold := entry.GetAttributeValue("lockoutThreshold"); lockoutThreshold != "" {
|
if lockoutThreshold := entry.GetAttributeValue("lockoutThreshold"); lockoutThreshold != "" {
|
||||||
policy["账户锁定阈值"] = lockoutThreshold + "次"
|
policy["账户锁定阈值"] = lockoutThreshold + "次"
|
||||||
|
Common.LogDebug(fmt.Sprintf("账户锁定阈值: %s次", lockoutThreshold))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(policy) > 0 {
|
||||||
|
Common.LogSuccess(fmt.Sprintf("成功获取域密码策略,共 %d 项配置", len(policy)))
|
||||||
|
|
||||||
|
// 安全性评估
|
||||||
|
minLengthInt, _ := strconv.Atoi(strings.TrimSuffix(policy["最小密码长度"], "个字符"))
|
||||||
|
if minLengthInt < 8 {
|
||||||
|
Common.LogDebug("警告:密码最小长度小于8个字符,存在安全风险")
|
||||||
|
}
|
||||||
|
|
||||||
|
lockoutThresholdInt, _ := strconv.Atoi(strings.TrimSuffix(policy["账户锁定阈值"], "次"))
|
||||||
|
if lockoutThresholdInt == 0 {
|
||||||
|
Common.LogDebug("警告:未启用账户锁定策略,存在暴力破解风险")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Common.LogDebug("未获取到任何密码策略配置")
|
||||||
}
|
}
|
||||||
|
|
||||||
return policy, nil
|
return policy, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取SPN信息
|
|
||||||
func (d *DomainInfo) GetSPNs() (map[string][]string, error) {
|
func (d *DomainInfo) GetSPNs() (map[string][]string, error) {
|
||||||
|
Common.LogDebug("开始查询SPN信息...")
|
||||||
|
|
||||||
searchRequest := ldap.NewSearchRequest(
|
searchRequest := ldap.NewSearchRequest(
|
||||||
d.baseDN,
|
d.baseDN,
|
||||||
ldap.ScopeWholeSubtree,
|
ldap.ScopeWholeSubtree,
|
||||||
@ -532,100 +719,139 @@ func (d *DomainInfo) GetSPNs() (map[string][]string, error) {
|
|||||||
|
|
||||||
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
|
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Common.LogError(fmt.Sprintf("查询SPN失败: %v", err))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
spns := make(map[string][]string)
|
spns := make(map[string][]string)
|
||||||
for _, entry := range sr.Entries {
|
for _, entry := range sr.Entries {
|
||||||
dn := entry.GetAttributeValue("distinguishedName")
|
dn := entry.GetAttributeValue("distinguishedName")
|
||||||
_ = entry.GetAttributeValue("cn")
|
cn := entry.GetAttributeValue("cn")
|
||||||
spnList := entry.GetAttributeValues("servicePrincipalName")
|
spnList := entry.GetAttributeValues("servicePrincipalName")
|
||||||
|
|
||||||
if len(spnList) > 0 {
|
if len(spnList) > 0 {
|
||||||
key := fmt.Sprintf("SPN:%s", dn)
|
key := fmt.Sprintf("SPN:%s", dn)
|
||||||
spns[key] = spnList
|
spns[key] = spnList
|
||||||
|
Common.LogDebug(fmt.Sprintf("发现SPN - CN: %s", cn))
|
||||||
|
for _, spn := range spnList {
|
||||||
|
Common.LogDebug(fmt.Sprintf(" - %s", spn))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(spns) > 0 {
|
||||||
|
Common.LogSuccess(fmt.Sprintf("共发现 %d 个SPN配置", len(spns)))
|
||||||
|
} else {
|
||||||
|
Common.LogDebug("未发现SPN配置")
|
||||||
|
}
|
||||||
|
|
||||||
return spns, nil
|
return spns, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取域控制器地址
|
|
||||||
func getDomainController() (string, error) {
|
func getDomainController() (string, error) {
|
||||||
// 先尝试使用 wmic 获取当前域名
|
Common.LogDebug("开始查询域控制器地址...")
|
||||||
|
|
||||||
|
// 尝试使用wmic获取当前域名
|
||||||
|
Common.LogDebug("正在使用wmic获取域名...")
|
||||||
cmd := exec.Command("wmic", "computersystem", "get", "domain")
|
cmd := exec.Command("wmic", "computersystem", "get", "domain")
|
||||||
output, err := cmd.Output()
|
output, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Common.LogError(fmt.Sprintf("获取域名失败: %v", err))
|
||||||
return "", fmt.Errorf("获取域名失败: %v", err)
|
return "", fmt.Errorf("获取域名失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
lines := strings.Split(string(output), "\n")
|
lines := strings.Split(string(output), "\n")
|
||||||
if len(lines) < 2 {
|
if len(lines) < 2 {
|
||||||
|
Common.LogError("wmic输出格式异常,未找到域名")
|
||||||
return "", fmt.Errorf("未找到域名")
|
return "", fmt.Errorf("未找到域名")
|
||||||
}
|
}
|
||||||
|
|
||||||
domain := strings.TrimSpace(lines[1])
|
domain := strings.TrimSpace(lines[1])
|
||||||
if domain == "" {
|
if domain == "" {
|
||||||
|
Common.LogError("获取到的域名为空")
|
||||||
return "", fmt.Errorf("域名为空")
|
return "", fmt.Errorf("域名为空")
|
||||||
}
|
}
|
||||||
|
Common.LogDebug(fmt.Sprintf("获取到域名: %s", domain))
|
||||||
|
|
||||||
// 使用nslookup查询域控制器
|
// 使用nslookup查询域控制器
|
||||||
|
Common.LogDebug(fmt.Sprintf("正在使用nslookup查询域控制器 (_ldap._tcp.dc._msdcs.%s)...", domain))
|
||||||
cmd = exec.Command("nslookup", "-type=SRV", fmt.Sprintf("_ldap._tcp.dc._msdcs.%s", domain))
|
cmd = exec.Command("nslookup", "-type=SRV", fmt.Sprintf("_ldap._tcp.dc._msdcs.%s", domain))
|
||||||
output, err = cmd.Output()
|
output, err = cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Common.LogError(fmt.Sprintf("nslookup查询失败: %v", err))
|
||||||
return "", fmt.Errorf("查询域控制器失败: %v", err)
|
return "", fmt.Errorf("查询域控制器失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解析nslookup输出
|
// 解析nslookup输出
|
||||||
lines = strings.Split(string(output), "\n")
|
lines = strings.Split(string(output), "\n")
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
// 查找包含域控制器主机名的行
|
|
||||||
if strings.Contains(line, "svr hostname") {
|
if strings.Contains(line, "svr hostname") {
|
||||||
parts := strings.Split(line, "=")
|
parts := strings.Split(line, "=")
|
||||||
if len(parts) > 1 {
|
if len(parts) > 1 {
|
||||||
dcHost := strings.TrimSpace(parts[1])
|
dcHost := strings.TrimSpace(parts[1])
|
||||||
// 移除末尾的点号(如果存在)
|
|
||||||
dcHost = strings.TrimSuffix(dcHost, ".")
|
dcHost = strings.TrimSuffix(dcHost, ".")
|
||||||
|
Common.LogSuccess(fmt.Sprintf("找到域控制器: %s", dcHost))
|
||||||
return dcHost, nil
|
return dcHost, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果上述方法失败,尝试直接使用域名前缀加上 DC 后缀
|
// 尝试使用域名前缀加DC后缀
|
||||||
|
Common.LogDebug("未从nslookup获取到域控制器,尝试使用域名前缀...")
|
||||||
domainParts := strings.Split(domain, ".")
|
domainParts := strings.Split(domain, ".")
|
||||||
if len(domainParts) > 0 {
|
if len(domainParts) > 0 {
|
||||||
return fmt.Sprintf("dc.%s", domain), nil
|
dcHost := fmt.Sprintf("dc.%s", domain)
|
||||||
|
Common.LogDebug(fmt.Sprintf("使用备选域控制器地址: %s", dcHost))
|
||||||
|
return dcHost, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Common.LogError("无法获取域控制器地址")
|
||||||
return "", fmt.Errorf("无法获取域控制器地址")
|
return "", fmt.Errorf("无法获取域控制器地址")
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDomainInfo() (*DomainInfo, error) {
|
func NewDomainInfo() (*DomainInfo, error) {
|
||||||
|
Common.LogDebug("开始初始化域信息...")
|
||||||
|
|
||||||
// 获取域控制器地址
|
// 获取域控制器地址
|
||||||
|
Common.LogDebug("正在获取域控制器地址...")
|
||||||
dcHost, err := getDomainController()
|
dcHost, err := getDomainController()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Common.LogError(fmt.Sprintf("获取域控制器失败: %v", err))
|
||||||
return nil, fmt.Errorf("获取域控制器失败: %v", err)
|
return nil, fmt.Errorf("获取域控制器失败: %v", err)
|
||||||
}
|
}
|
||||||
|
Common.LogDebug(fmt.Sprintf("成功获取域控制器地址: %s", dcHost))
|
||||||
|
|
||||||
// 创建SSPI客户端
|
// 创建SSPI客户端
|
||||||
|
Common.LogDebug("正在创建SSPI客户端...")
|
||||||
ldapClient, err := gssapi.NewSSPIClient()
|
ldapClient, err := gssapi.NewSSPIClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Common.LogError(fmt.Sprintf("创建SSPI客户端失败: %v", err))
|
||||||
return nil, fmt.Errorf("创建SSPI客户端失败: %v", err)
|
return nil, fmt.Errorf("创建SSPI客户端失败: %v", err)
|
||||||
}
|
}
|
||||||
defer ldapClient.Close()
|
defer ldapClient.Close()
|
||||||
|
Common.LogDebug("SSPI客户端创建成功")
|
||||||
|
|
||||||
// 创建LDAP连接
|
// 创建LDAP连接
|
||||||
|
Common.LogDebug(fmt.Sprintf("正在连接LDAP服务器 ldap://%s:389", dcHost))
|
||||||
conn, err := ldap.DialURL(fmt.Sprintf("ldap://%s:389", dcHost))
|
conn, err := ldap.DialURL(fmt.Sprintf("ldap://%s:389", dcHost))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Common.LogError(fmt.Sprintf("LDAP连接失败: %v", err))
|
||||||
return nil, fmt.Errorf("LDAP连接失败: %v", err)
|
return nil, fmt.Errorf("LDAP连接失败: %v", err)
|
||||||
}
|
}
|
||||||
|
Common.LogDebug("LDAP连接建立成功")
|
||||||
|
|
||||||
// 使用GSSAPI进行绑定
|
// 使用GSSAPI进行绑定
|
||||||
|
Common.LogDebug(fmt.Sprintf("正在进行GSSAPI绑定 (ldap/%s)...", dcHost))
|
||||||
err = conn.GSSAPIBind(ldapClient, fmt.Sprintf("ldap/%s", dcHost), "")
|
err = conn.GSSAPIBind(ldapClient, fmt.Sprintf("ldap/%s", dcHost), "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
conn.Close()
|
conn.Close()
|
||||||
|
Common.LogError(fmt.Sprintf("GSSAPI绑定失败: %v", err))
|
||||||
return nil, fmt.Errorf("GSSAPI绑定失败: %v", err)
|
return nil, fmt.Errorf("GSSAPI绑定失败: %v", err)
|
||||||
}
|
}
|
||||||
|
Common.LogDebug("GSSAPI绑定成功")
|
||||||
|
|
||||||
// 先执行一个根搜索来获取defaultNamingContext
|
// 获取defaultNamingContext
|
||||||
|
Common.LogDebug("正在查询defaultNamingContext...")
|
||||||
searchRequest := ldap.NewSearchRequest(
|
searchRequest := ldap.NewSearchRequest(
|
||||||
"",
|
"",
|
||||||
ldap.ScopeBaseObject,
|
ldap.ScopeBaseObject,
|
||||||
@ -639,20 +865,23 @@ func NewDomainInfo() (*DomainInfo, error) {
|
|||||||
result, err := conn.Search(searchRequest)
|
result, err := conn.Search(searchRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
conn.Close()
|
conn.Close()
|
||||||
|
Common.LogError(fmt.Sprintf("获取defaultNamingContext失败: %v", err))
|
||||||
return nil, fmt.Errorf("获取defaultNamingContext失败: %v", err)
|
return nil, fmt.Errorf("获取defaultNamingContext失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(result.Entries) == 0 {
|
if len(result.Entries) == 0 {
|
||||||
conn.Close()
|
conn.Close()
|
||||||
|
Common.LogError("未找到defaultNamingContext")
|
||||||
return nil, fmt.Errorf("未找到defaultNamingContext")
|
return nil, fmt.Errorf("未找到defaultNamingContext")
|
||||||
}
|
}
|
||||||
|
|
||||||
baseDN := result.Entries[0].GetAttributeValue("defaultNamingContext")
|
baseDN := result.Entries[0].GetAttributeValue("defaultNamingContext")
|
||||||
if baseDN == "" {
|
if baseDN == "" {
|
||||||
|
Common.LogDebug("defaultNamingContext为空,使用备选方法获取BaseDN")
|
||||||
baseDN = getDomainDN(dcHost) // 使用备选方法
|
baseDN = getDomainDN(dcHost) // 使用备选方法
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Using BaseDN: %s\n", baseDN) // 添加调试输出
|
Common.LogSuccess(fmt.Sprintf("初始化完成,使用BaseDN: %s", baseDN))
|
||||||
|
|
||||||
return &DomainInfo{
|
return &DomainInfo{
|
||||||
conn: conn,
|
conn: conn,
|
||||||
@ -660,45 +889,22 @@ func NewDomainInfo() (*DomainInfo, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否在域环境中
|
|
||||||
func IsInDomain() bool {
|
|
||||||
// 获取计算机域成员身份信息
|
|
||||||
var joinStatus uint32
|
|
||||||
var buffer uint32
|
|
||||||
|
|
||||||
ret, _, _ := syscall.NewLazyDLL("netapi32.dll").NewProc("NetGetJoinInformation").Call(
|
|
||||||
0,
|
|
||||||
uintptr(unsafe.Pointer(&joinStatus)),
|
|
||||||
uintptr(unsafe.Pointer(&buffer)),
|
|
||||||
)
|
|
||||||
|
|
||||||
if ret == 0 {
|
|
||||||
// 清理资源
|
|
||||||
syscall.NewLazyDLL("netapi32.dll").NewProc("NetApiBufferFree").Call(uintptr(buffer))
|
|
||||||
// 检查是否为域成员
|
|
||||||
return joinStatus == 3 // 3 = NetSetupDomainName 表示是域成员
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func DCInfoScan(info *Common.HostInfo) (err error) {
|
func DCInfoScan(info *Common.HostInfo) (err error) {
|
||||||
if !IsInDomain() {
|
|
||||||
return fmt.Errorf("当前系统不在域环境中")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建DomainInfo实例,使用当前用户凭据
|
// 创建DomainInfo实例
|
||||||
|
Common.LogDebug("正在初始化域信息...")
|
||||||
di, err := NewDomainInfo()
|
di, err := NewDomainInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
Common.LogError(fmt.Sprintf("初始化域信息失败: %v", err))
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
defer di.Close()
|
defer di.Close()
|
||||||
|
|
||||||
// 首先获取特殊计算机列表
|
// 获取特殊计算机列表
|
||||||
specialComputers, err := di.GetSpecialComputers()
|
specialComputers, err := di.GetSpecialComputers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("获取特殊计算机失败: %v", err)
|
Common.LogError(fmt.Sprintf("获取特殊计算机失败: %v", err))
|
||||||
} else {
|
} else {
|
||||||
// 按固定顺序显示结果
|
|
||||||
categories := []string{
|
categories := []string{
|
||||||
"SQL服务器",
|
"SQL服务器",
|
||||||
"CA服务器",
|
"CA服务器",
|
||||||
@ -706,145 +912,130 @@ func DCInfoScan(info *Common.HostInfo) (err error) {
|
|||||||
"Exchange服务器",
|
"Exchange服务器",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Common.LogSuccess("[*] 特殊计算机信息:")
|
||||||
for _, category := range categories {
|
for _, category := range categories {
|
||||||
if computers, ok := specialComputers[category]; ok {
|
if computers, ok := specialComputers[category]; ok {
|
||||||
fmt.Printf("%s:\n", category)
|
Common.LogSuccess(fmt.Sprintf("[+] %s:", category))
|
||||||
for _, computer := range computers {
|
for _, computer := range computers {
|
||||||
fmt.Printf("\t%s\n", computer)
|
Common.LogSuccess(fmt.Sprintf(" %s", computer))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Println()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取域用户
|
||||||
users, err := di.GetDomainUsers()
|
users, err := di.GetDomainUsers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("获取域用户失败: %v", err)
|
Common.LogError(fmt.Sprintf("获取域用户失败: %v", err))
|
||||||
return
|
} else {
|
||||||
}
|
Common.LogSuccess("[*] 域用户列表:")
|
||||||
|
|
||||||
// 打印用户信息
|
|
||||||
fmt.Println("域用户:")
|
|
||||||
for _, user := range users {
|
for _, user := range users {
|
||||||
fmt.Println("\t" + user)
|
Common.LogSuccess(fmt.Sprintf(" %s", user))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取域管理员
|
// 获取域管理员
|
||||||
admins, err := di.GetDomainAdmins()
|
admins, err := di.GetDomainAdmins()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("获取域管理员失败: %v", err)
|
Common.LogError(fmt.Sprintf("获取域管理员失败: %v", err))
|
||||||
return
|
} else {
|
||||||
}
|
Common.LogSuccess("[*] 域管理员列表:")
|
||||||
|
|
||||||
// 打印域管理员信息
|
|
||||||
fmt.Println("域管理员:")
|
|
||||||
for _, admin := range admins {
|
for _, admin := range admins {
|
||||||
fmt.Println("\t" + admin)
|
Common.LogSuccess(fmt.Sprintf(" %s", admin))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取组织单位
|
// 获取组织单位
|
||||||
ous, err := di.GetOUs()
|
ous, err := di.GetOUs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("获取组织单位失败: %v", err)
|
Common.LogError(fmt.Sprintf("获取组织单位失败: %v", err))
|
||||||
return
|
} else {
|
||||||
}
|
Common.LogSuccess("[*] 组织单位:")
|
||||||
|
|
||||||
// 打印组织单位信息
|
|
||||||
fmt.Println("组织单位:")
|
|
||||||
for _, ou := range ous {
|
for _, ou := range ous {
|
||||||
fmt.Println("\t" + ou)
|
Common.LogSuccess(fmt.Sprintf(" %s", ou))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取域计算机
|
// 获取域计算机
|
||||||
computers, err := di.GetComputers()
|
computers, err := di.GetComputers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("获取域计算机失败: %v", err)
|
Common.LogError(fmt.Sprintf("获取域计算机失败: %v", err))
|
||||||
return
|
} else {
|
||||||
}
|
Common.LogSuccess("[*] 域计算机:")
|
||||||
|
|
||||||
// 打印域计算机信息
|
|
||||||
fmt.Println("域计算机:")
|
|
||||||
for _, computer := range computers {
|
for _, computer := range computers {
|
||||||
fmt.Printf("\t%s", computer.Name)
|
|
||||||
if computer.OperatingSystem != "" {
|
if computer.OperatingSystem != "" {
|
||||||
fmt.Printf(" --> %s", computer.OperatingSystem)
|
Common.LogSuccess(fmt.Sprintf(" %s --> %s", computer.Name, computer.OperatingSystem))
|
||||||
|
} else {
|
||||||
|
Common.LogSuccess(fmt.Sprintf(" %s", computer.Name))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fmt.Println()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取并显示信任域关系
|
// 获取信任域关系
|
||||||
trustDomains, err := di.GetTrustDomains()
|
trustDomains, err := di.GetTrustDomains()
|
||||||
if err == nil {
|
if err == nil && len(trustDomains) > 0 {
|
||||||
fmt.Println("信任域关系:")
|
Common.LogSuccess("[*] 信任域关系:")
|
||||||
for _, domain := range trustDomains {
|
for _, domain := range trustDomains {
|
||||||
fmt.Printf("\t%s\n", domain)
|
Common.LogSuccess(fmt.Sprintf(" %s", domain))
|
||||||
}
|
}
|
||||||
fmt.Println()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取并显示域管理员组信息
|
// 获取域管理员组信息
|
||||||
adminGroups, err := di.GetAdminGroups()
|
adminGroups, err := di.GetAdminGroups()
|
||||||
if err == nil {
|
if err == nil && len(adminGroups) > 0 {
|
||||||
|
Common.LogSuccess("[*] 管理员组信息:")
|
||||||
for groupName, members := range adminGroups {
|
for groupName, members := range adminGroups {
|
||||||
fmt.Printf("%s成员:\n", groupName)
|
Common.LogSuccess(fmt.Sprintf("[+] %s成员:", groupName))
|
||||||
for _, member := range members {
|
for _, member := range members {
|
||||||
fmt.Printf("\t%s\n", member)
|
Common.LogSuccess(fmt.Sprintf(" %s", member))
|
||||||
}
|
}
|
||||||
fmt.Println()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取并显示委派信息
|
// 获取委派信息
|
||||||
delegations, err := di.GetDelegation()
|
delegations, err := di.GetDelegation()
|
||||||
if err == nil {
|
if err == nil && len(delegations) > 0 {
|
||||||
|
Common.LogSuccess("[*] 委派信息:")
|
||||||
for delegationType, entries := range delegations {
|
for delegationType, entries := range delegations {
|
||||||
fmt.Printf("%s:\n", delegationType)
|
Common.LogSuccess(fmt.Sprintf("[+] %s:", delegationType))
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
fmt.Printf("\t%s\n", entry)
|
Common.LogSuccess(fmt.Sprintf(" %s", entry))
|
||||||
}
|
}
|
||||||
fmt.Println()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取并显示AS-REP Roasting漏洞用户
|
// 获取AS-REP Roasting漏洞用户
|
||||||
asrepUsers, err := di.GetAsrepRoastUsers()
|
asrepUsers, err := di.GetAsrepRoastUsers()
|
||||||
if err == nil {
|
if err == nil && len(asrepUsers) > 0 {
|
||||||
fmt.Println("AS-REP弱口令账户:")
|
Common.LogSuccess("[*] AS-REP弱口令账户:")
|
||||||
for _, user := range asrepUsers {
|
for _, user := range asrepUsers {
|
||||||
fmt.Printf("\t%s\n", user)
|
Common.LogSuccess(fmt.Sprintf(" %s", user))
|
||||||
}
|
}
|
||||||
fmt.Println()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取并显示域密码策略
|
// 获取域密码策略
|
||||||
passwordPolicy, err := di.GetPasswordPolicy()
|
passwordPolicy, err := di.GetPasswordPolicy()
|
||||||
if err == nil {
|
if err == nil && len(passwordPolicy) > 0 {
|
||||||
fmt.Println("域密码策略:")
|
Common.LogSuccess("[*] 域密码策略:")
|
||||||
for key, value := range passwordPolicy {
|
for key, value := range passwordPolicy {
|
||||||
fmt.Printf("\t%s: %s\n", key, value)
|
Common.LogSuccess(fmt.Sprintf(" %s: %s", key, value))
|
||||||
}
|
}
|
||||||
fmt.Println()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取SPN信息
|
// 获取SPN信息
|
||||||
spns, err := di.GetSPNs()
|
spns, err := di.GetSPNs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("获取SPN信息失败: %v", err)
|
Common.LogError(fmt.Sprintf("获取SPN信息失败: %v", err))
|
||||||
return
|
} else if len(spns) > 0 {
|
||||||
|
Common.LogSuccess("[*] SPN信息:")
|
||||||
|
for dn, spnList := range spns {
|
||||||
|
Common.LogSuccess(fmt.Sprintf("[+] %s", dn))
|
||||||
|
for _, spn := range spnList {
|
||||||
|
Common.LogSuccess(fmt.Sprintf(" %s", spn))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 打印SPN信息
|
|
||||||
if len(spns) > 0 {
|
|
||||||
for dn, spnList := range spns {
|
|
||||||
fmt.Println(dn)
|
|
||||||
for _, spn := range spnList {
|
|
||||||
fmt.Printf("\t%s\n", spn)
|
|
||||||
}
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fmt.Println("未发现SPN信息\n")
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,26 +279,30 @@ func IsAdmin() bool {
|
|||||||
func MiniDump(info *Common.HostInfo) (err error) {
|
func MiniDump(info *Common.HostInfo) (err error) {
|
||||||
// 先检查管理员权限
|
// 先检查管理员权限
|
||||||
if !IsAdmin() {
|
if !IsAdmin() {
|
||||||
|
Common.LogError("需要管理员权限才能执行此操作")
|
||||||
return fmt.Errorf("需要管理员权限才能执行此操作")
|
return fmt.Errorf("需要管理员权限才能执行此操作")
|
||||||
}
|
}
|
||||||
|
|
||||||
pm, err := NewProcessManager()
|
pm, err := NewProcessManager()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Common.LogError(fmt.Sprintf("初始化进程管理器失败: %v", err))
|
||||||
return fmt.Errorf("初始化进程管理器失败: %v", err)
|
return fmt.Errorf("初始化进程管理器失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查找 lsass.exe
|
// 查找 lsass.exe
|
||||||
pid, err := pm.FindProcess("lsass.exe")
|
pid, err := pm.FindProcess("lsass.exe")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Common.LogError(fmt.Sprintf("查找进程失败: %v", err))
|
||||||
return fmt.Errorf("查找进程失败: %v", err)
|
return fmt.Errorf("查找进程失败: %v", err)
|
||||||
}
|
}
|
||||||
fmt.Printf("找到进程 lsass.exe, PID: %d\n", pid)
|
Common.LogSuccess(fmt.Sprintf("找到进程 lsass.exe, PID: %d", pid))
|
||||||
|
|
||||||
// 提升权限
|
// 提升权限
|
||||||
if err := pm.ElevatePrivileges(); err != nil {
|
if err := pm.ElevatePrivileges(); err != nil {
|
||||||
|
Common.LogError(fmt.Sprintf("提升权限失败: %v", err))
|
||||||
return fmt.Errorf("提升权限失败: %v", err)
|
return fmt.Errorf("提升权限失败: %v", err)
|
||||||
}
|
}
|
||||||
fmt.Println("成功提升进程权限")
|
Common.LogSuccess("成功提升进程权限")
|
||||||
|
|
||||||
// 创建输出路径
|
// 创建输出路径
|
||||||
outputPath := filepath.Join(".", fmt.Sprintf("fscan-%d.dmp", pid))
|
outputPath := filepath.Join(".", fmt.Sprintf("fscan-%d.dmp", pid))
|
||||||
@ -306,9 +310,10 @@ func MiniDump(info *Common.HostInfo) (err error) {
|
|||||||
// 执行转储
|
// 执行转储
|
||||||
if err := pm.DumpProcess(pid, outputPath); err != nil {
|
if err := pm.DumpProcess(pid, outputPath); err != nil {
|
||||||
os.Remove(outputPath)
|
os.Remove(outputPath)
|
||||||
|
Common.LogError(fmt.Sprintf("进程转储失败: %v", err))
|
||||||
return fmt.Errorf("进程转储失败: %v", err)
|
return fmt.Errorf("进程转储失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("成功将进程内存转储到文件: %s\n", outputPath)
|
Common.LogSuccess(fmt.Sprintf("成功将进程内存转储到文件: %s", outputPath))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ import (
|
|||||||
"golang.org/x/text/encoding/simplifiedchinese"
|
"golang.org/x/text/encoding/simplifiedchinese"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WebTitle 获取Web标题并执行扫描
|
// WebTitle 获取Web标题和指纹信息
|
||||||
func WebTitle(info *Common.HostInfo) error {
|
func WebTitle(info *Common.HostInfo) error {
|
||||||
// 获取网站标题信息
|
// 获取网站标题信息
|
||||||
err, CheckData := GOWebTitle(info)
|
err, CheckData := GOWebTitle(info)
|
||||||
@ -31,10 +31,8 @@ func WebTitle(info *Common.HostInfo) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据配置决定是否执行漏洞扫描
|
// 输出错误信息(如果有)
|
||||||
if !Common.DisablePoc && err == nil {
|
if err != nil {
|
||||||
WebScan.WebScan(info)
|
|
||||||
} else {
|
|
||||||
errlog := fmt.Sprintf("网站标题 %v %v", info.Url, err)
|
errlog := fmt.Sprintf("网站标题 %v %v", info.Url, err)
|
||||||
Common.LogError(errlog)
|
Common.LogError(errlog)
|
||||||
}
|
}
|
||||||
|
@ -19,22 +19,43 @@ var AllPocs []*lib.Poc
|
|||||||
|
|
||||||
// WebScan 执行Web漏洞扫描
|
// WebScan 执行Web漏洞扫描
|
||||||
func WebScan(info *Common.HostInfo) {
|
func WebScan(info *Common.HostInfo) {
|
||||||
// 确保POC只初始化一次
|
|
||||||
once.Do(initpoc)
|
once.Do(initpoc)
|
||||||
|
|
||||||
// 构建扫描信息
|
|
||||||
var pocinfo = Common.Pocinfo
|
var pocinfo = Common.Pocinfo
|
||||||
urlParts := strings.Split(info.Url, "/")
|
|
||||||
pocinfo.Target = strings.Join(urlParts[:3], "/")
|
|
||||||
|
|
||||||
// 执行扫描
|
// 自动构建URL
|
||||||
if pocinfo.PocName != "" {
|
if info.Url == "" {
|
||||||
// 指定POC扫描
|
info.Url = fmt.Sprintf("http://%s:%s", info.Host, info.Ports)
|
||||||
|
}
|
||||||
|
|
||||||
|
urlParts := strings.Split(info.Url, "/")
|
||||||
|
|
||||||
|
// 检查切片长度并构建目标URL
|
||||||
|
if len(urlParts) >= 3 {
|
||||||
|
pocinfo.Target = strings.Join(urlParts[:3], "/")
|
||||||
|
} else {
|
||||||
|
pocinfo.Target = info.Url
|
||||||
|
}
|
||||||
|
|
||||||
|
Common.LogDebug(fmt.Sprintf("扫描目标: %s", pocinfo.Target))
|
||||||
|
|
||||||
|
// 如果是直接调用WebPoc(没有指定pocName),执行所有POC
|
||||||
|
if pocinfo.PocName == "" && len(info.Infostr) == 0 {
|
||||||
|
Common.LogDebug("直接调用WebPoc,执行所有POC")
|
||||||
Execute(pocinfo)
|
Execute(pocinfo)
|
||||||
} else {
|
} else {
|
||||||
// 根据指纹信息选择POC扫描
|
// 根据指纹信息选择性执行POC
|
||||||
|
if len(info.Infostr) > 0 {
|
||||||
for _, infostr := range info.Infostr {
|
for _, infostr := range info.Infostr {
|
||||||
pocinfo.PocName = lib.CheckInfoPoc(infostr)
|
pocinfo.PocName = lib.CheckInfoPoc(infostr)
|
||||||
|
if pocinfo.PocName != "" {
|
||||||
|
Common.LogDebug(fmt.Sprintf("根据指纹 %s 执行对应POC", infostr))
|
||||||
|
Execute(pocinfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if pocinfo.PocName != "" {
|
||||||
|
// 指定了特定的POC
|
||||||
|
Common.LogDebug(fmt.Sprintf("执行指定POC: %s", pocinfo.PocName))
|
||||||
Execute(pocinfo)
|
Execute(pocinfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -42,6 +63,8 @@ func WebScan(info *Common.HostInfo) {
|
|||||||
|
|
||||||
// Execute 执行具体的POC检测
|
// Execute 执行具体的POC检测
|
||||||
func Execute(PocInfo Common.PocInfo) {
|
func Execute(PocInfo Common.PocInfo) {
|
||||||
|
Common.LogDebug(fmt.Sprintf("开始执行POC检测,目标: %s", PocInfo.Target))
|
||||||
|
|
||||||
// 创建基础HTTP请求
|
// 创建基础HTTP请求
|
||||||
req, err := http.NewRequest("GET", PocInfo.Target, nil)
|
req, err := http.NewRequest("GET", PocInfo.Target, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -59,12 +82,16 @@ func Execute(PocInfo Common.PocInfo) {
|
|||||||
|
|
||||||
// 根据名称筛选POC并执行
|
// 根据名称筛选POC并执行
|
||||||
pocs := filterPoc(PocInfo.PocName)
|
pocs := filterPoc(PocInfo.PocName)
|
||||||
|
Common.LogDebug(fmt.Sprintf("筛选到的POC数量: %d", len(pocs)))
|
||||||
lib.CheckMultiPoc(req, pocs, Common.PocNum)
|
lib.CheckMultiPoc(req, pocs, Common.PocNum)
|
||||||
}
|
}
|
||||||
|
|
||||||
// initpoc 初始化POC加载
|
// initpoc 初始化POC加载
|
||||||
func initpoc() {
|
func initpoc() {
|
||||||
|
Common.LogDebug("开始初始化POC")
|
||||||
|
|
||||||
if Common.PocPath == "" {
|
if Common.PocPath == "" {
|
||||||
|
Common.LogDebug("从内置目录加载POC")
|
||||||
// 从嵌入的POC目录加载
|
// 从嵌入的POC目录加载
|
||||||
entries, err := Pocs.ReadDir("pocs")
|
entries, err := Pocs.ReadDir("pocs")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -78,9 +105,11 @@ func initpoc() {
|
|||||||
if strings.HasSuffix(filename, ".yaml") || strings.HasSuffix(filename, ".yml") {
|
if strings.HasSuffix(filename, ".yaml") || strings.HasSuffix(filename, ".yml") {
|
||||||
if poc, err := lib.LoadPoc(filename, Pocs); err == nil && poc != nil {
|
if poc, err := lib.LoadPoc(filename, Pocs); err == nil && poc != nil {
|
||||||
AllPocs = append(AllPocs, poc)
|
AllPocs = append(AllPocs, poc)
|
||||||
|
} else if err != nil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Common.LogDebug(fmt.Sprintf("内置POC加载完成,共加载 %d 个", len(AllPocs)))
|
||||||
} else {
|
} else {
|
||||||
// 从指定目录加载POC
|
// 从指定目录加载POC
|
||||||
Common.LogSuccess(fmt.Sprintf("从目录加载POC: %s", Common.PocPath))
|
Common.LogSuccess(fmt.Sprintf("从目录加载POC: %s", Common.PocPath))
|
||||||
@ -92,6 +121,7 @@ func initpoc() {
|
|||||||
if !info.IsDir() && (strings.HasSuffix(path, ".yaml") || strings.HasSuffix(path, ".yml")) {
|
if !info.IsDir() && (strings.HasSuffix(path, ".yaml") || strings.HasSuffix(path, ".yml")) {
|
||||||
if poc, err := lib.LoadPocbyPath(path); err == nil && poc != nil {
|
if poc, err := lib.LoadPocbyPath(path); err == nil && poc != nil {
|
||||||
AllPocs = append(AllPocs, poc)
|
AllPocs = append(AllPocs, poc)
|
||||||
|
} else if err != nil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -100,12 +130,16 @@ func initpoc() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
Common.LogError(fmt.Sprintf("加载外部POC失败: %v", err))
|
Common.LogError(fmt.Sprintf("加载外部POC失败: %v", err))
|
||||||
}
|
}
|
||||||
|
Common.LogDebug(fmt.Sprintf("外部POC加载完成,共加载 %d 个", len(AllPocs)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// filterPoc 根据POC名称筛选
|
// filterPoc 根据POC名称筛选
|
||||||
func filterPoc(pocname string) []*lib.Poc {
|
func filterPoc(pocname string) []*lib.Poc {
|
||||||
|
Common.LogDebug(fmt.Sprintf("开始筛选POC,筛选条件: %s", pocname))
|
||||||
|
|
||||||
if pocname == "" {
|
if pocname == "" {
|
||||||
|
Common.LogDebug(fmt.Sprintf("未指定POC名称,返回所有POC: %d 个", len(AllPocs)))
|
||||||
return AllPocs
|
return AllPocs
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,5 +149,6 @@ func filterPoc(pocname string) []*lib.Poc {
|
|||||||
matchedPocs = append(matchedPocs, poc)
|
matchedPocs = append(matchedPocs, poc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Common.LogDebug(fmt.Sprintf("POC筛选完成,匹配到 %d 个", len(matchedPocs)))
|
||||||
return matchedPocs
|
return matchedPocs
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user