From 75aeee5215041e7b62cdcc1acadabfe709cee84a Mon Sep 17 00:00:00 2001 From: ZacharyZcR <2903735704@qq.com> Date: Sat, 4 Jan 2025 11:49:59 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E5=9F=9F=E6=8E=A2?= =?UTF-8?q?=E6=B5=8B=E6=98=BE=E7=A4=BA=EF=BC=8C=E8=B0=83=E6=95=B4Web?= =?UTF-8?q?=E6=89=AB=E6=8F=8F=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Common/Config.go | 24 +-- Common/Flag.go | 9 +- Common/Log.go | 14 +- Common/Parse.go | 36 +--- Common/ParseScanMode.go | 6 +- Core/PortScan.go | 10 +- Core/Registry.go | 2 +- Core/Scanner.go | 12 +- Plugins/DCInfo.go | 465 ++++++++++++++++++++++++++++------------ Plugins/MiniDump.go | 11 +- Plugins/WebTitle.go | 8 +- WebScan/WebScan.go | 55 ++++- WebScan/lib/Check.go | 2 +- 13 files changed, 424 insertions(+), 230 deletions(-) diff --git a/Common/Config.go b/Common/Config.go index dbcfef2..1111b60 100644 --- a/Common/Config.go +++ b/Common/Config.go @@ -876,14 +876,15 @@ var ( AddPasswords string // 原PassAdd // 扫描配置 - ScanMode string // 原Scantype - ThreadNum int // 原Threads - UseSynScan bool - Timeout int64 = 3 - LiveTop int - DisablePing bool // 原NoPing - UsePing bool // 原Ping - Command string + ScanMode string // 原Scantype + ThreadNum int // 原Threads + UseSynScan bool + Timeout int64 = 3 + LiveTop int + DisablePing bool // 原NoPing + UsePing bool // 原Ping + Command string + SkipFingerprint bool // 本地扫描配置 LocalScan bool @@ -896,17 +897,14 @@ var ( PortsFile string // 原PortFile // Web配置 - TargetURL string // 原URL - URLsFile string // 原UrlFile URLs []string // 原Urls WebTimeout int64 = 5 HttpProxy string // 原Proxy Socks5Proxy string // POC配置 - PocPath string - Pocinfo PocInfo - DisablePoc bool // 原NoPoc + PocPath string + Pocinfo PocInfo // Redis配置 RedisFile string diff --git a/Common/Flag.go b/Common/Flag.go index 1bca7f6..30231d9 100644 --- a/Common/Flag.go +++ b/Common/Flag.go @@ -185,7 +185,6 @@ func Flag(Info *HostInfo) { " - Port: 端口扫描模式\n"+ " - ICMP: ICMP存活探测\n"+ " - Local: 本地信息收集\n\n"+ - " - UDP: UDP扫描模式\n\n"+ "单个插件模式(小写):\n"+ " Web类: web, fcgi\n"+ " 数据库类: mysql, mssql, redis, mongodb, postgres, oracle, memcached\n"+ @@ -199,9 +198,10 @@ func Flag(Info *HostInfo) { flag.BoolVar(&DisablePing, "np", false, "禁用主机存活探测") flag.BoolVar(&UsePing, "ping", false, "使用系统ping命令替代ICMP探测") 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", "", "从文件中读取目标主机列表") @@ -211,8 +211,6 @@ func Flag(Info *HostInfo) { flag.StringVar(&PortsFile, "portf", "", "从文件中读取端口列表") // Web配置 - flag.StringVar(&TargetURL, "u", "", "指定目标URL") - flag.StringVar(&URLsFile, "uf", "", "从文件中读取URL列表") flag.StringVar(&Cookie, "cookie", "", "设置HTTP请求Cookie") flag.Int64Var(&WebTimeout, "wt", 5, "设置Web请求超时时间(单位:秒)") flag.StringVar(&HttpProxy, "proxy", "", "设置HTTP代理服务器") @@ -221,7 +219,6 @@ func Flag(Info *HostInfo) { // POC配置 flag.StringVar(&PocPath, "pocpath", "", "指定自定义POC文件路径") 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(&DnsLog, "dns", false, "启用dnslog进行漏洞验证") flag.IntVar(&PocNum, "num", 20, "设置POC扫描并发数") @@ -248,7 +245,7 @@ func Flag(Info *HostInfo) { flag.BoolVar(&NoColor, "nocolor", false, "禁用彩色输出显示") flag.BoolVar(&JsonFormat, "json", false, "以JSON格式输出结果") flag.StringVar(&LogLevel, "log", LogLevelInfo, "日志输出级别(ALL/SUCCESS/ERROR/INFO/DEBUG)") - flag.BoolVar(&NoProgress, "noprogress", false, "禁用进度条显示") + flag.BoolVar(&NoProgress, "nopg", false, "禁用进度条显示") flag.Parse() } diff --git a/Common/Log.go b/Common/Log.go index 867647d..6259bcd 100644 --- a/Common/Log.go +++ b/Common/Log.go @@ -83,9 +83,17 @@ func formatLogMessage(entry *LogEntry) string { // 修改 printLog 函数 func printLog(entry *LogEntry) { - if LogLevel != LogLevelAll && - entry.Level != LogLevel && - !(LogLevel == LogLevelInfo && (entry.Level == LogLevelInfo || entry.Level == LogLevelSuccess)) { + // 默认情况(LogLevelInfo)下打印 INFO、SUCCESS、ERROR + if LogLevel == LogLevelInfo { + 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 } diff --git a/Common/Parse.go b/Common/Parse.go index b925957..d8029cf 100644 --- a/Common/Parse.go +++ b/Common/Parse.go @@ -114,40 +114,6 @@ func ParsePass(Info *HostInfo) error { 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 != "" { ports, err := Readfile(PortsFile) @@ -206,7 +172,7 @@ func Readfile(filename string) ([]string, error) { // ParseInput 解析和验证输入参数配置 func ParseInput(Info *HostInfo) error { // 检查必要的目标参数 - if Info.Host == "" && HostsFile == "" && TargetURL == "" && URLsFile == "" { + if Info.Host == "" && HostsFile == "" { LogError("未指定扫描目标") flag.Usage() return fmt.Errorf("必须指定扫描目标") diff --git a/Common/ParseScanMode.go b/Common/ParseScanMode.go index 9b232cb..f6a92a1 100644 --- a/Common/ParseScanMode.go +++ b/Common/ParseScanMode.go @@ -18,7 +18,7 @@ const ( // 插件分类映射表 - 所有插件名使用小写 var pluginGroups = map[string][]string{ ModeAll: { - "web", "fcgi", // web类 + "webtitle", "webpoc", "fcgi", // web类 "mysql", "mssql", "redis", "mongodb", "postgres", // 数据库类 "oracle", "memcached", "elasticsearch", "rabbitmq", "kafka", "activemq", "cassandra", "neo4j", // 数据库类 "ftp", "ssh", "telnet", "smb", "rdp", "vnc", "netbios", "ldap", "smtp", "imap", "pop3", "snmp", "modbus", "rsync", // 服务类 @@ -26,14 +26,14 @@ var pluginGroups = map[string][]string{ "findnet", // 其他 }, ModeBasic: { - "web", "ftp", "ssh", "smb", "findnet", + "webtitle", "ftp", "ssh", "smb", "findnet", }, ModeDatabase: { "mysql", "mssql", "redis", "mongodb", "postgres", "oracle", "memcached", "elasticsearch", "rabbitmq", "kafka", "activemq", "cassandra", "neo4j", }, ModeWeb: { - "web", "fcgi", + "webtitle", "webpoc", "fcgi", }, ModeService: { "ftp", "ssh", "telnet", "smb", "rdp", "vnc", "netbios", "ldap", "smtp", "imap", "pop3", "modbus", "rsync", diff --git a/Core/PortScan.go b/Core/PortScan.go index 5a7ab8d..b47c448 100644 --- a/Core/PortScan.go +++ b/Core/PortScan.go @@ -126,27 +126,23 @@ func PortConnect(addr Addr, results chan<- ScanResult, timeout int64, wg *sync.W Port: addr.port, } - // 进行服务识别 - if conn != nil { + // 只在未跳过指纹识别时进行服务识别 + if !Common.SkipFingerprint && conn != nil { scanner := NewPortInfoScanner(addr.ip, addr.port, conn, time.Duration(timeout)*time.Second) if serviceInfo, err := scanner.Identify(); err == nil { result.Service = serviceInfo - // 打印服务识别信息 var logMsg strings.Builder logMsg.WriteString(fmt.Sprintf("服务识别 %s => ", address)) - // 添加服务名称 if serviceInfo.Name != "unknown" { logMsg.WriteString(fmt.Sprintf("[%s]", serviceInfo.Name)) } - // 添加版本信息 if serviceInfo.Version != "" { logMsg.WriteString(fmt.Sprintf(" 版本:%s", serviceInfo.Version)) } - // 添加其他有用的信息 if v, ok := serviceInfo.Extras["vendor_product"]; ok && 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)) } - // 如果有Banner且长度合适,也输出 if len(serviceInfo.Banner) > 0 && len(serviceInfo.Banner) < 100 { 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 } diff --git a/Core/Registry.go b/Core/Registry.go index e1b1516..021e7cd 100644 --- a/Core/Registry.go +++ b/Core/Registry.go @@ -195,7 +195,7 @@ func init() { }) // web 相关插件添加 WebPorts 配置 - Common.RegisterPlugin("web", Common.ScanPlugin{ + Common.RegisterPlugin("webtitle", Common.ScanPlugin{ Name: "WebTitle", Ports: Common.ParsePortsFromString(Common.WebPorts), // 将 WebPorts 字符串解析为端口数组 ScanFunc: Plugins.WebTitle, diff --git a/Core/Scanner.go b/Core/Scanner.go index bf09da7..5607838 100644 --- a/Core/Scanner.go +++ b/Core/Scanner.go @@ -115,7 +115,7 @@ func executeScans(targets []Common.HostInfo, ch *chan struct{}, wg *sync.WaitGro pluginsToRun = []string{mode} isSinglePlugin = true } - + loadedPlugins := make([]string, 0) // 先遍历一遍计算实际要执行的任务数 actualTasks := 0 @@ -222,16 +222,18 @@ func executeScans(targets []Common.HostInfo, ch *chan struct{}, wg *sync.WaitGro // finishScan 完成扫描任务 func finishScan(wg *sync.WaitGroup) { wg.Wait() - // 确保进度条完成 - Common.ProgressBar.Finish() - fmt.Println() // 添加一个换行 + // 确保进度条完成,只在存在进度条时调用 + if Common.ProgressBar != nil { + Common.ProgressBar.Finish() + fmt.Println() // 添加一个换行 + } Common.LogSuccess(fmt.Sprintf("扫描已完成: %v/%v", Common.End, Common.Num)) } // Mutex用于保护共享资源的并发访问 var Mutex = &sync.Mutex{} -// AddScan 也需要修改 +// AddScan func AddScan(plugin string, info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) { *ch <- struct{}{} wg.Add(1) diff --git a/Plugins/DCInfo.go b/Plugins/DCInfo.go index 2db8bf8..0e7e265 100644 --- a/Plugins/DCInfo.go +++ b/Plugins/DCInfo.go @@ -4,16 +4,12 @@ package Plugins import ( "fmt" + "github.com/go-ldap/ldap/v3" "github.com/go-ldap/ldap/v3/gssapi" "github.com/shadow1ng/fscan/Common" - "log" "os/exec" "strconv" "strings" - "syscall" - "unsafe" - - "github.com/go-ldap/ldap/v3" ) type DomainInfo struct { @@ -28,7 +24,8 @@ func (d *DomainInfo) Close() { } func (d *DomainInfo) GetCAComputers() ([]string, error) { - // 在Configuration容器中查找CA服务器 + Common.LogDebug("开始查询域内CA服务器...") + searchRequest := ldap.NewSearchRequest( "CN=Configuration,"+d.baseDN, ldap.ScopeWholeSubtree, @@ -36,13 +33,14 @@ func (d *DomainInfo) GetCAComputers() ([]string, error) { 0, 0, false, - "(&(objectCategory=pKIEnrollmentService))", // CA服务器的查询条件 + "(&(objectCategory=pKIEnrollmentService))", []string{"cn", "dNSHostName"}, nil, ) sr, err := d.conn.SearchWithPaging(searchRequest, 10000) if err != nil { + Common.LogError(fmt.Sprintf("查询CA服务器失败: %v", err)) return nil, err } @@ -51,12 +49,22 @@ func (d *DomainInfo) GetCAComputers() ([]string, error) { cn := entry.GetAttributeValue("cn") if 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 } func (d *DomainInfo) GetExchangeServers() ([]string, error) { + Common.LogDebug("开始查询Exchange服务器...") + searchRequest := ldap.NewSearchRequest( d.baseDN, ldap.ScopeWholeSubtree, @@ -71,6 +79,7 @@ func (d *DomainInfo) GetExchangeServers() ([]string, error) { sr, err := d.conn.SearchWithPaging(searchRequest, 10000) if err != nil { + Common.LogError(fmt.Sprintf("查询Exchange服务器失败: %v", err)) return nil, err } @@ -79,6 +88,7 @@ func (d *DomainInfo) GetExchangeServers() ([]string, error) { for _, member := range entry.GetAttributeValues("member") { if 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 { exchangeServers = exchangeServers[1:] + Common.LogDebug("移除第一个条目") + } + + if len(exchangeServers) > 0 { + Common.LogSuccess(fmt.Sprintf("共发现 %d 个Exchange服务器", len(exchangeServers))) + } else { + Common.LogDebug("未发现Exchange服务器") } return exchangeServers, nil } func (d *DomainInfo) GetMsSqlServers() ([]string, error) { + Common.LogDebug("开始查询SQL Server服务器...") + searchRequest := ldap.NewSearchRequest( d.baseDN, ldap.ScopeWholeSubtree, @@ -106,6 +125,7 @@ func (d *DomainInfo) GetMsSqlServers() ([]string, error) { sr, err := d.conn.SearchWithPaging(searchRequest, 10000) if err != nil { + Common.LogError(fmt.Sprintf("查询SQL Server失败: %v", err)) return nil, err } @@ -114,28 +134,43 @@ func (d *DomainInfo) GetMsSqlServers() ([]string, error) { name := entry.GetAttributeValue("name") if 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 } func (d *DomainInfo) GetSpecialComputers() (map[string][]string, error) { + Common.LogDebug("开始查询特殊计算机...") results := make(map[string][]string) // 获取SQL Server + Common.LogDebug("正在查询SQL Server...") sqlServers, err := d.GetMsSqlServers() if err == nil && len(sqlServers) > 0 { results["SQL服务器"] = sqlServers + } else if err != nil { + Common.LogError(fmt.Sprintf("查询SQL Server时出错: %v", err)) } // 获取CA服务器 + Common.LogDebug("正在查询CA服务器...") caComputers, err := d.GetCAComputers() if err == nil && len(caComputers) > 0 { results["CA服务器"] = caComputers + } else if err != nil { + Common.LogError(fmt.Sprintf("查询CA服务器时出错: %v", err)) } // 获取域控制器 + Common.LogDebug("正在查询域控制器...") dcQuery := ldap.NewSearchRequest( d.baseDN, ldap.ScopeWholeSubtree, @@ -154,24 +189,42 @@ func (d *DomainInfo) GetSpecialComputers() (map[string][]string, error) { name := entry.GetAttributeValue("cn") if name != "" { dcs = append(dcs, name) + Common.LogDebug(fmt.Sprintf("发现域控制器: %s", name)) } } if len(dcs) > 0 { results["域控制器"] = dcs + Common.LogSuccess(fmt.Sprintf("共发现 %d 个域控制器", len(dcs))) + } else { + Common.LogDebug("未发现域控制器") } + } else { + Common.LogError(fmt.Sprintf("查询域控制器时出错: %v", err)) } // 获取Exchange服务器 + Common.LogDebug("正在查询Exchange服务器...") exchangeServers, err := d.GetExchangeServers() if err == nil && len(exchangeServers) > 0 { 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 } -// 获取域用户 func (d *DomainInfo) GetDomainUsers() ([]string, error) { + Common.LogDebug("开始查询域用户...") searchRequest := ldap.NewSearchRequest( d.baseDN, @@ -187,19 +240,31 @@ func (d *DomainInfo) GetDomainUsers() ([]string, error) { sr, err := d.conn.SearchWithPaging(searchRequest, 10000) if err != nil { + Common.LogError(fmt.Sprintf("查询域用户失败: %v", err)) return nil, err } var users []string 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 } -// 获取域管理员 func (d *DomainInfo) GetDomainAdmins() ([]string, error) { + Common.LogDebug("开始查询域管理员...") + searchRequest := ldap.NewSearchRequest( d.baseDN, ldap.ScopeWholeSubtree, @@ -214,15 +279,15 @@ func (d *DomainInfo) GetDomainAdmins() ([]string, error) { sr, err := d.conn.SearchWithPaging(searchRequest, 10000) if err != nil { + Common.LogError(fmt.Sprintf("查询Domain Admins组失败: %v", err)) return nil, err } var admins []string if len(sr.Entries) > 0 { - // 获取组成员 members := sr.Entries[0].GetAttributeValues("member") + Common.LogDebug(fmt.Sprintf("发现 %d 个Domain Admins组成员", len(members))) - // 对每个成员DN执行查询以获取其sAMAccountName for _, memberDN := range members { memberSearch := ldap.NewSearchRequest( memberDN, @@ -238,23 +303,32 @@ func (d *DomainInfo) GetDomainAdmins() ([]string, error) { memberResult, err := d.conn.Search(memberSearch) if err != nil { - continue // 跳过出错的成员 + Common.LogError(fmt.Sprintf("查询成员 %s 失败: %v", memberDN, err)) + continue } if len(memberResult.Entries) > 0 { samAccountName := memberResult.Entries[0].GetAttributeValue("sAMAccountName") if 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 } -// 获取组织单位(OU) func (d *DomainInfo) GetOUs() ([]string, error) { + Common.LogDebug("开始查询组织单位(OU)...") + searchRequest := ldap.NewSearchRequest( d.baseDN, ldap.ScopeWholeSubtree, @@ -269,6 +343,7 @@ func (d *DomainInfo) GetOUs() ([]string, error) { sr, err := d.conn.SearchWithPaging(searchRequest, 10000) if err != nil { + Common.LogError(fmt.Sprintf("查询OU失败: %v", err)) return nil, err } @@ -277,12 +352,22 @@ func (d *DomainInfo) GetOUs() ([]string, error) { ou := entry.GetAttributeValue("ou") if 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 } func (d *DomainInfo) GetComputers() ([]Computer, error) { + Common.LogDebug("开始查询域内计算机...") + searchRequest := ldap.NewSearchRequest( d.baseDN, ldap.ScopeWholeSubtree, @@ -297,6 +382,7 @@ func (d *DomainInfo) GetComputers() ([]Computer, error) { sr, err := d.conn.SearchWithPaging(searchRequest, 10000) if err != nil { + Common.LogError(fmt.Sprintf("查询计算机失败: %v", err)) return nil, err } @@ -308,7 +394,30 @@ func (d *DomainInfo) GetComputers() ([]Computer, error) { DNSHostName: entry.GetAttributeValue("dNSHostName"), } 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 } @@ -319,8 +428,9 @@ type Computer struct { DNSHostName string } -// 获取信任域关系 func (d *DomainInfo) GetTrustDomains() ([]string, error) { + Common.LogDebug("开始查询域信任关系...") + searchRequest := ldap.NewSearchRequest( d.baseDN, ldap.ScopeWholeSubtree, @@ -335,6 +445,7 @@ func (d *DomainInfo) GetTrustDomains() ([]string, error) { sr, err := d.conn.SearchWithPaging(searchRequest, 10000) if err != nil { + Common.LogError(fmt.Sprintf("查询信任域失败: %v", err)) return nil, err } @@ -343,13 +454,22 @@ func (d *DomainInfo) GetTrustDomains() ([]string, error) { cn := entry.GetAttributeValue("cn") if 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 } -// 获取域管理员组成员 func (d *DomainInfo) GetAdminGroups() (map[string][]string, error) { + Common.LogDebug("开始查询管理员组信息...") + adminGroups := map[string]string{ "Domain Admins": "(&(objectClass=group)(cn=Domain 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) for groupName, filter := range adminGroups { + Common.LogDebug(fmt.Sprintf("正在查询 %s 组...", groupName)) + searchRequest := ldap.NewSearchRequest( d.baseDN, ldap.ScopeWholeSubtree, @@ -373,6 +495,7 @@ func (d *DomainInfo) GetAdminGroups() (map[string][]string, error) { sr, err := d.conn.SearchWithPaging(searchRequest, 10000) if err != nil { + Common.LogError(fmt.Sprintf("查询 %s 组失败: %v", groupName, err)) continue } @@ -380,14 +503,28 @@ func (d *DomainInfo) GetAdminGroups() (map[string][]string, error) { members := sr.Entries[0].GetAttributeValues("member") if len(members) > 0 { 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 } -// 获取委派信息 func (d *DomainInfo) GetDelegation() (map[string][]string, error) { + Common.LogDebug("开始查询委派信息...") + delegationQueries := map[string]string{ "非约束委派": "(&(objectCategory=computer)(userAccountControl:1.2.840.113556.1.4.803:=524288))", "约束委派": "(msDS-AllowedToDelegateTo=*)", @@ -397,6 +534,8 @@ func (d *DomainInfo) GetDelegation() (map[string][]string, error) { results := make(map[string][]string) for delegationType, query := range delegationQueries { + Common.LogDebug(fmt.Sprintf("正在查询%s...", delegationType)) + searchRequest := ldap.NewSearchRequest( d.baseDN, ldap.ScopeWholeSubtree, @@ -411,6 +550,7 @@ func (d *DomainInfo) GetDelegation() (map[string][]string, error) { sr, err := d.conn.SearchWithPaging(searchRequest, 10000) if err != nil { + Common.LogError(fmt.Sprintf("查询%s失败: %v", delegationType, err)) continue } @@ -419,18 +559,31 @@ func (d *DomainInfo) GetDelegation() (map[string][]string, error) { cn := entry.GetAttributeValue("cn") if cn != "" { entries = append(entries, cn) + Common.LogDebug(fmt.Sprintf("发现%s: %s", delegationType, cn)) } } if len(entries) > 0 { 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 } // 获取AS-REP Roasting漏洞用户 func (d *DomainInfo) GetAsrepRoastUsers() ([]string, error) { + Common.LogDebug("开始查询AS-REP Roasting漏洞用户...") + searchRequest := ldap.NewSearchRequest( d.baseDN, ldap.ScopeWholeSubtree, @@ -445,6 +598,7 @@ func (d *DomainInfo) GetAsrepRoastUsers() ([]string, error) { sr, err := d.conn.SearchWithPaging(searchRequest, 10000) if err != nil { + Common.LogError(fmt.Sprintf("查询AS-REP Roasting漏洞用户失败: %v", err)) return nil, err } @@ -453,13 +607,22 @@ func (d *DomainInfo) GetAsrepRoastUsers() ([]string, error) { name := entry.GetAttributeValue("sAMAccountName") if 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 } -// 获取域密码策略 func (d *DomainInfo) GetPasswordPolicy() (map[string]string, error) { + Common.LogDebug("开始查询域密码策略...") + searchRequest := ldap.NewSearchRequest( d.baseDN, ldap.ScopeBaseObject, @@ -482,42 +645,66 @@ func (d *DomainInfo) GetPasswordPolicy() (map[string]string, error) { sr, err := d.conn.Search(searchRequest) if err != nil { + Common.LogError(fmt.Sprintf("查询密码策略失败: %v", err)) return nil, err } if len(sr.Entries) == 0 { + Common.LogError("未找到密码策略信息") return nil, fmt.Errorf("未找到密码策略信息") } policy := make(map[string]string) entry := sr.Entries[0] - // 转换最大密码期限(负值,以100纳秒为单位) + // 转换最大密码期限 if maxAge := entry.GetAttributeValue("maxPwdAge"); maxAge != "" { maxAgeInt, _ := strconv.ParseInt(maxAge, 10, 64) if maxAgeInt != 0 { days := float64(maxAgeInt) * -1 / float64(864000000000) policy["最大密码期限"] = fmt.Sprintf("%.0f天", days) + Common.LogDebug(fmt.Sprintf("最大密码期限: %.0f天", days)) } } if minLength := entry.GetAttributeValue("minPwdLength"); minLength != "" { policy["最小密码长度"] = minLength + "个字符" + Common.LogDebug(fmt.Sprintf("最小密码长度: %s个字符", minLength)) } if historyLength := entry.GetAttributeValue("pwdHistoryLength"); historyLength != "" { policy["密码历史长度"] = historyLength + "个" + Common.LogDebug(fmt.Sprintf("密码历史长度: %s个", historyLength)) } if lockoutThreshold := entry.GetAttributeValue("lockoutThreshold"); 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 } -// 获取SPN信息 func (d *DomainInfo) GetSPNs() (map[string][]string, error) { + Common.LogDebug("开始查询SPN信息...") + searchRequest := ldap.NewSearchRequest( d.baseDN, ldap.ScopeWholeSubtree, @@ -532,100 +719,139 @@ func (d *DomainInfo) GetSPNs() (map[string][]string, error) { sr, err := d.conn.SearchWithPaging(searchRequest, 10000) if err != nil { + Common.LogError(fmt.Sprintf("查询SPN失败: %v", err)) return nil, err } spns := make(map[string][]string) for _, entry := range sr.Entries { dn := entry.GetAttributeValue("distinguishedName") - _ = entry.GetAttributeValue("cn") + cn := entry.GetAttributeValue("cn") spnList := entry.GetAttributeValues("servicePrincipalName") + if len(spnList) > 0 { key := fmt.Sprintf("SPN:%s", dn) 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 } -// 获取域控制器地址 func getDomainController() (string, error) { - // 先尝试使用 wmic 获取当前域名 + Common.LogDebug("开始查询域控制器地址...") + + // 尝试使用wmic获取当前域名 + Common.LogDebug("正在使用wmic获取域名...") cmd := exec.Command("wmic", "computersystem", "get", "domain") output, err := cmd.Output() if err != nil { + Common.LogError(fmt.Sprintf("获取域名失败: %v", err)) return "", fmt.Errorf("获取域名失败: %v", err) } lines := strings.Split(string(output), "\n") if len(lines) < 2 { + Common.LogError("wmic输出格式异常,未找到域名") return "", fmt.Errorf("未找到域名") } domain := strings.TrimSpace(lines[1]) if domain == "" { + Common.LogError("获取到的域名为空") 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)) output, err = cmd.Output() if err != nil { + Common.LogError(fmt.Sprintf("nslookup查询失败: %v", err)) return "", fmt.Errorf("查询域控制器失败: %v", err) } - // 解析 nslookup 输出 + // 解析nslookup输出 lines = strings.Split(string(output), "\n") for _, line := range lines { - // 查找包含域控制器主机名的行 if strings.Contains(line, "svr hostname") { parts := strings.Split(line, "=") if len(parts) > 1 { dcHost := strings.TrimSpace(parts[1]) - // 移除末尾的点号(如果存在) dcHost = strings.TrimSuffix(dcHost, ".") + Common.LogSuccess(fmt.Sprintf("找到域控制器: %s", dcHost)) return dcHost, nil } } } - // 如果上述方法失败,尝试直接使用域名前缀加上 DC 后缀 + // 尝试使用域名前缀加DC后缀 + Common.LogDebug("未从nslookup获取到域控制器,尝试使用域名前缀...") domainParts := strings.Split(domain, ".") 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("无法获取域控制器地址") } func NewDomainInfo() (*DomainInfo, error) { + Common.LogDebug("开始初始化域信息...") + // 获取域控制器地址 + Common.LogDebug("正在获取域控制器地址...") dcHost, err := getDomainController() if err != nil { + Common.LogError(fmt.Sprintf("获取域控制器失败: %v", err)) return nil, fmt.Errorf("获取域控制器失败: %v", err) } + Common.LogDebug(fmt.Sprintf("成功获取域控制器地址: %s", dcHost)) // 创建SSPI客户端 + Common.LogDebug("正在创建SSPI客户端...") ldapClient, err := gssapi.NewSSPIClient() if err != nil { + Common.LogError(fmt.Sprintf("创建SSPI客户端失败: %v", err)) return nil, fmt.Errorf("创建SSPI客户端失败: %v", err) } defer ldapClient.Close() + Common.LogDebug("SSPI客户端创建成功") // 创建LDAP连接 + Common.LogDebug(fmt.Sprintf("正在连接LDAP服务器 ldap://%s:389", dcHost)) conn, err := ldap.DialURL(fmt.Sprintf("ldap://%s:389", dcHost)) if err != nil { + Common.LogError(fmt.Sprintf("LDAP连接失败: %v", err)) return nil, fmt.Errorf("LDAP连接失败: %v", err) } + Common.LogDebug("LDAP连接建立成功") // 使用GSSAPI进行绑定 + Common.LogDebug(fmt.Sprintf("正在进行GSSAPI绑定 (ldap/%s)...", dcHost)) err = conn.GSSAPIBind(ldapClient, fmt.Sprintf("ldap/%s", dcHost), "") if err != nil { conn.Close() + Common.LogError(fmt.Sprintf("GSSAPI绑定失败: %v", err)) return nil, fmt.Errorf("GSSAPI绑定失败: %v", err) } + Common.LogDebug("GSSAPI绑定成功") - // 先执行一个根搜索来获取defaultNamingContext + // 获取defaultNamingContext + Common.LogDebug("正在查询defaultNamingContext...") searchRequest := ldap.NewSearchRequest( "", ldap.ScopeBaseObject, @@ -639,20 +865,23 @@ func NewDomainInfo() (*DomainInfo, error) { result, err := conn.Search(searchRequest) if err != nil { conn.Close() + Common.LogError(fmt.Sprintf("获取defaultNamingContext失败: %v", err)) return nil, fmt.Errorf("获取defaultNamingContext失败: %v", err) } if len(result.Entries) == 0 { conn.Close() + Common.LogError("未找到defaultNamingContext") return nil, fmt.Errorf("未找到defaultNamingContext") } baseDN := result.Entries[0].GetAttributeValue("defaultNamingContext") if baseDN == "" { + Common.LogDebug("defaultNamingContext为空,使用备选方法获取BaseDN") baseDN = getDomainDN(dcHost) // 使用备选方法 } - fmt.Printf("Using BaseDN: %s\n", baseDN) // 添加调试输出 + Common.LogSuccess(fmt.Sprintf("初始化完成,使用BaseDN: %s", baseDN)) return &DomainInfo{ conn: conn, @@ -660,45 +889,22 @@ func NewDomainInfo() (*DomainInfo, error) { }, 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) { - if !IsInDomain() { - return fmt.Errorf("当前系统不在域环境中") - } - // 创建DomainInfo实例,使用当前用户凭据 + // 创建DomainInfo实例 + Common.LogDebug("正在初始化域信息...") di, err := NewDomainInfo() if err != nil { - log.Fatal(err) + Common.LogError(fmt.Sprintf("初始化域信息失败: %v", err)) + return err } defer di.Close() - // 首先获取特殊计算机列表 + // 获取特殊计算机列表 specialComputers, err := di.GetSpecialComputers() if err != nil { - log.Printf("获取特殊计算机失败: %v", err) + Common.LogError(fmt.Sprintf("获取特殊计算机失败: %v", err)) } else { - // 按固定顺序显示结果 categories := []string{ "SQL服务器", "CA服务器", @@ -706,145 +912,130 @@ func DCInfoScan(info *Common.HostInfo) (err error) { "Exchange服务器", } + Common.LogSuccess("[*] 特殊计算机信息:") for _, category := range categories { if computers, ok := specialComputers[category]; ok { - fmt.Printf("%s:\n", category) + Common.LogSuccess(fmt.Sprintf("[+] %s:", category)) for _, computer := range computers { - fmt.Printf("\t%s\n", computer) + Common.LogSuccess(fmt.Sprintf(" %s", computer)) } } } - fmt.Println() } + // 获取域用户 users, err := di.GetDomainUsers() if err != nil { - log.Printf("获取域用户失败: %v", err) - return - } - - // 打印用户信息 - fmt.Println("域用户:") - for _, user := range users { - fmt.Println("\t" + user) + Common.LogError(fmt.Sprintf("获取域用户失败: %v", err)) + } else { + Common.LogSuccess("[*] 域用户列表:") + for _, user := range users { + Common.LogSuccess(fmt.Sprintf(" %s", user)) + } } // 获取域管理员 admins, err := di.GetDomainAdmins() if err != nil { - log.Printf("获取域管理员失败: %v", err) - return - } - - // 打印域管理员信息 - fmt.Println("域管理员:") - for _, admin := range admins { - fmt.Println("\t" + admin) + Common.LogError(fmt.Sprintf("获取域管理员失败: %v", err)) + } else { + Common.LogSuccess("[*] 域管理员列表:") + for _, admin := range admins { + Common.LogSuccess(fmt.Sprintf(" %s", admin)) + } } // 获取组织单位 ous, err := di.GetOUs() if err != nil { - log.Printf("获取组织单位失败: %v", err) - return - } - - // 打印组织单位信息 - fmt.Println("组织单位:") - for _, ou := range ous { - fmt.Println("\t" + ou) + Common.LogError(fmt.Sprintf("获取组织单位失败: %v", err)) + } else { + Common.LogSuccess("[*] 组织单位:") + for _, ou := range ous { + Common.LogSuccess(fmt.Sprintf(" %s", ou)) + } } // 获取域计算机 computers, err := di.GetComputers() if err != nil { - log.Printf("获取域计算机失败: %v", err) - return - } - - // 打印域计算机信息 - fmt.Println("域计算机:") - for _, computer := range computers { - fmt.Printf("\t%s", computer.Name) - if computer.OperatingSystem != "" { - fmt.Printf(" --> %s", computer.OperatingSystem) + Common.LogError(fmt.Sprintf("获取域计算机失败: %v", err)) + } else { + Common.LogSuccess("[*] 域计算机:") + for _, computer := range computers { + if 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() - if err == nil { - fmt.Println("信任域关系:") + if err == nil && len(trustDomains) > 0 { + Common.LogSuccess("[*] 信任域关系:") for _, domain := range trustDomains { - fmt.Printf("\t%s\n", domain) + Common.LogSuccess(fmt.Sprintf(" %s", domain)) } - fmt.Println() } - // 获取并显示域管理员组信息 + // 获取域管理员组信息 adminGroups, err := di.GetAdminGroups() - if err == nil { + if err == nil && len(adminGroups) > 0 { + Common.LogSuccess("[*] 管理员组信息:") for groupName, members := range adminGroups { - fmt.Printf("%s成员:\n", groupName) + Common.LogSuccess(fmt.Sprintf("[+] %s成员:", groupName)) for _, member := range members { - fmt.Printf("\t%s\n", member) + Common.LogSuccess(fmt.Sprintf(" %s", member)) } - fmt.Println() } } - // 获取并显示委派信息 + // 获取委派信息 delegations, err := di.GetDelegation() - if err == nil { + if err == nil && len(delegations) > 0 { + Common.LogSuccess("[*] 委派信息:") for delegationType, entries := range delegations { - fmt.Printf("%s:\n", delegationType) + Common.LogSuccess(fmt.Sprintf("[+] %s:", delegationType)) 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() - if err == nil { - fmt.Println("AS-REP弱口令账户:") + if err == nil && len(asrepUsers) > 0 { + Common.LogSuccess("[*] AS-REP弱口令账户:") for _, user := range asrepUsers { - fmt.Printf("\t%s\n", user) + Common.LogSuccess(fmt.Sprintf(" %s", user)) } - fmt.Println() } - // 获取并显示域密码策略 + // 获取域密码策略 passwordPolicy, err := di.GetPasswordPolicy() - if err == nil { - fmt.Println("域密码策略:") + if err == nil && len(passwordPolicy) > 0 { + Common.LogSuccess("[*] 域密码策略:") for key, value := range passwordPolicy { - fmt.Printf("\t%s: %s\n", key, value) + Common.LogSuccess(fmt.Sprintf(" %s: %s", key, value)) } - fmt.Println() } // 获取SPN信息 spns, err := di.GetSPNs() if err != nil { - log.Printf("获取SPN信息失败: %v", err) - return + Common.LogError(fmt.Sprintf("获取SPN信息失败: %v", err)) + } 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 } diff --git a/Plugins/MiniDump.go b/Plugins/MiniDump.go index 7078551..2671f3c 100644 --- a/Plugins/MiniDump.go +++ b/Plugins/MiniDump.go @@ -279,26 +279,30 @@ func IsAdmin() bool { func MiniDump(info *Common.HostInfo) (err error) { // 先检查管理员权限 if !IsAdmin() { + Common.LogError("需要管理员权限才能执行此操作") return fmt.Errorf("需要管理员权限才能执行此操作") } pm, err := NewProcessManager() if err != nil { + Common.LogError(fmt.Sprintf("初始化进程管理器失败: %v", err)) return fmt.Errorf("初始化进程管理器失败: %v", err) } // 查找 lsass.exe pid, err := pm.FindProcess("lsass.exe") if err != nil { + Common.LogError(fmt.Sprintf("查找进程失败: %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 { + Common.LogError(fmt.Sprintf("提升权限失败: %v", err)) return fmt.Errorf("提升权限失败: %v", err) } - fmt.Println("成功提升进程权限") + Common.LogSuccess("成功提升进程权限") // 创建输出路径 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 { os.Remove(outputPath) + Common.LogError(fmt.Sprintf("进程转储失败: %v", err)) return fmt.Errorf("进程转储失败: %v", err) } - fmt.Printf("成功将进程内存转储到文件: %s\n", outputPath) + Common.LogSuccess(fmt.Sprintf("成功将进程内存转储到文件: %s", outputPath)) return nil } diff --git a/Plugins/WebTitle.go b/Plugins/WebTitle.go index 4abdcbb..653f920 100644 --- a/Plugins/WebTitle.go +++ b/Plugins/WebTitle.go @@ -18,7 +18,7 @@ import ( "golang.org/x/text/encoding/simplifiedchinese" ) -// WebTitle 获取Web标题并执行扫描 +// WebTitle 获取Web标题和指纹信息 func WebTitle(info *Common.HostInfo) error { // 获取网站标题信息 err, CheckData := GOWebTitle(info) @@ -31,10 +31,8 @@ func WebTitle(info *Common.HostInfo) error { } } - // 根据配置决定是否执行漏洞扫描 - if !Common.DisablePoc && err == nil { - WebScan.WebScan(info) - } else { + // 输出错误信息(如果有) + if err != nil { errlog := fmt.Sprintf("网站标题 %v %v", info.Url, err) Common.LogError(errlog) } diff --git a/WebScan/WebScan.go b/WebScan/WebScan.go index dfc4332..1f4b78f 100644 --- a/WebScan/WebScan.go +++ b/WebScan/WebScan.go @@ -19,22 +19,43 @@ var AllPocs []*lib.Poc // WebScan 执行Web漏洞扫描 func WebScan(info *Common.HostInfo) { - // 确保POC只初始化一次 once.Do(initpoc) - // 构建扫描信息 var pocinfo = Common.Pocinfo - urlParts := strings.Split(info.Url, "/") - pocinfo.Target = strings.Join(urlParts[:3], "/") - // 执行扫描 - if pocinfo.PocName != "" { - // 指定POC扫描 + // 自动构建URL + if info.Url == "" { + 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) } else { - // 根据指纹信息选择POC扫描 - for _, infostr := range info.Infostr { - pocinfo.PocName = lib.CheckInfoPoc(infostr) + // 根据指纹信息选择性执行POC + if len(info.Infostr) > 0 { + for _, infostr := range info.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) } } @@ -42,6 +63,8 @@ func WebScan(info *Common.HostInfo) { // Execute 执行具体的POC检测 func Execute(PocInfo Common.PocInfo) { + Common.LogDebug(fmt.Sprintf("开始执行POC检测,目标: %s", PocInfo.Target)) + // 创建基础HTTP请求 req, err := http.NewRequest("GET", PocInfo.Target, nil) if err != nil { @@ -59,12 +82,16 @@ func Execute(PocInfo Common.PocInfo) { // 根据名称筛选POC并执行 pocs := filterPoc(PocInfo.PocName) + Common.LogDebug(fmt.Sprintf("筛选到的POC数量: %d", len(pocs))) lib.CheckMultiPoc(req, pocs, Common.PocNum) } // initpoc 初始化POC加载 func initpoc() { + Common.LogDebug("开始初始化POC") + if Common.PocPath == "" { + Common.LogDebug("从内置目录加载POC") // 从嵌入的POC目录加载 entries, err := Pocs.ReadDir("pocs") if err != nil { @@ -78,9 +105,11 @@ func initpoc() { if strings.HasSuffix(filename, ".yaml") || strings.HasSuffix(filename, ".yml") { if poc, err := lib.LoadPoc(filename, Pocs); err == nil && poc != nil { AllPocs = append(AllPocs, poc) + } else if err != nil { } } } + Common.LogDebug(fmt.Sprintf("内置POC加载完成,共加载 %d 个", len(AllPocs))) } else { // 从指定目录加载POC 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 poc, err := lib.LoadPocbyPath(path); err == nil && poc != nil { AllPocs = append(AllPocs, poc) + } else if err != nil { } } return nil @@ -100,12 +130,16 @@ func initpoc() { if err != nil { Common.LogError(fmt.Sprintf("加载外部POC失败: %v", err)) } + Common.LogDebug(fmt.Sprintf("外部POC加载完成,共加载 %d 个", len(AllPocs))) } } // filterPoc 根据POC名称筛选 func filterPoc(pocname string) []*lib.Poc { + Common.LogDebug(fmt.Sprintf("开始筛选POC,筛选条件: %s", pocname)) + if pocname == "" { + Common.LogDebug(fmt.Sprintf("未指定POC名称,返回所有POC: %d 个", len(AllPocs))) return AllPocs } @@ -115,5 +149,6 @@ func filterPoc(pocname string) []*lib.Poc { matchedPocs = append(matchedPocs, poc) } } + Common.LogDebug(fmt.Sprintf("POC筛选完成,匹配到 %d 个", len(matchedPocs))) return matchedPocs } diff --git a/WebScan/lib/Check.go b/WebScan/lib/Check.go index 7dd442e..91968eb 100644 --- a/WebScan/lib/Check.go +++ b/WebScan/lib/Check.go @@ -637,7 +637,7 @@ func clustersend(oReq *http.Request, variableMap map[string]interface{}, req *Re } return false, err } - + // 检查表达式执行结果 if fmt.Sprintf("%v", out) == "false" { return false, nil