fscan/Plugins/DCInfo.go

1051 lines
27 KiB
Go
Raw Normal View History

2024-12-28 06:34:37 +08:00
//go:build windows
2024-12-28 05:43:22 +08:00
package Plugins
import (
"fmt"
"github.com/go-ldap/ldap/v3"
2024-12-28 05:43:22 +08:00
"github.com/go-ldap/ldap/v3/gssapi"
"github.com/shadow1ng/fscan/Common"
"os/exec"
"strconv"
"strings"
)
type DomainInfo struct {
conn *ldap.Conn
baseDN string
}
func (d *DomainInfo) Close() {
if d.conn != nil {
d.conn.Close()
}
}
func (d *DomainInfo) GetCAComputers() ([]string, error) {
Common.LogDebug("开始查询域内CA服务器...")
2024-12-28 05:43:22 +08:00
searchRequest := ldap.NewSearchRequest(
"CN=Configuration,"+d.baseDN,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
0,
0,
false,
"(&(objectCategory=pKIEnrollmentService))",
2024-12-28 05:43:22 +08:00
[]string{"cn", "dNSHostName"},
nil,
)
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
if err != nil {
Common.LogError(fmt.Sprintf("查询CA服务器失败: %v", err))
2024-12-28 05:43:22 +08:00
return nil, err
}
var caComputers []string
for _, entry := range sr.Entries {
cn := entry.GetAttributeValue("cn")
if cn != "" {
caComputers = append(caComputers, cn)
Common.LogDebug(fmt.Sprintf("发现CA服务器: %s", cn))
2024-12-28 05:43:22 +08:00
}
}
if len(caComputers) > 0 {
Common.LogSuccess(fmt.Sprintf("共发现 %d 个CA服务器", len(caComputers)))
} else {
Common.LogDebug("未发现CA服务器")
}
2024-12-28 05:43:22 +08:00
return caComputers, nil
}
func (d *DomainInfo) GetExchangeServers() ([]string, error) {
Common.LogDebug("开始查询Exchange服务器...")
2024-12-28 05:43:22 +08:00
searchRequest := ldap.NewSearchRequest(
d.baseDN,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
0,
0,
false,
"(&(objectCategory=group)(cn=Exchange Servers))",
[]string{"member"},
nil,
)
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
if err != nil {
Common.LogError(fmt.Sprintf("查询Exchange服务器失败: %v", err))
2024-12-28 05:43:22 +08:00
return nil, err
}
var exchangeServers []string
for _, entry := range sr.Entries {
for _, member := range entry.GetAttributeValues("member") {
if member != "" {
exchangeServers = append(exchangeServers, member)
Common.LogDebug(fmt.Sprintf("发现Exchange服务器成员: %s", member))
2024-12-28 05:43:22 +08:00
}
}
}
// 移除第一个条目(如果存在)
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服务器")
2024-12-28 05:43:22 +08:00
}
return exchangeServers, nil
}
func (d *DomainInfo) GetMsSqlServers() ([]string, error) {
Common.LogDebug("开始查询SQL Server服务器...")
2024-12-28 05:43:22 +08:00
searchRequest := ldap.NewSearchRequest(
d.baseDN,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
0,
0,
false,
"(&(objectClass=computer)(servicePrincipalName=MSSQLSvc*))",
[]string{"name"},
nil,
)
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
if err != nil {
Common.LogError(fmt.Sprintf("查询SQL Server失败: %v", err))
2024-12-28 05:43:22 +08:00
return nil, err
}
var sqlServers []string
for _, entry := range sr.Entries {
name := entry.GetAttributeValue("name")
if name != "" {
sqlServers = append(sqlServers, name)
Common.LogDebug(fmt.Sprintf("发现SQL Server: %s", name))
2024-12-28 05:43:22 +08:00
}
}
if len(sqlServers) > 0 {
Common.LogSuccess(fmt.Sprintf("共发现 %d 个SQL Server", len(sqlServers)))
} else {
Common.LogDebug("未发现SQL Server")
}
2024-12-28 05:43:22 +08:00
return sqlServers, nil
}
func (d *DomainInfo) GetSpecialComputers() (map[string][]string, error) {
Common.LogDebug("开始查询特殊计算机...")
2024-12-28 05:43:22 +08:00
results := make(map[string][]string)
// 获取SQL Server
Common.LogDebug("正在查询SQL Server...")
2024-12-28 05:43:22 +08:00
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))
2024-12-28 05:43:22 +08:00
}
// 获取CA服务器
Common.LogDebug("正在查询CA服务器...")
2024-12-28 05:43:22 +08:00
caComputers, err := d.GetCAComputers()
if err == nil && len(caComputers) > 0 {
results["CA服务器"] = caComputers
} else if err != nil {
Common.LogError(fmt.Sprintf("查询CA服务器时出错: %v", err))
2024-12-28 05:43:22 +08:00
}
// 获取域控制器
Common.LogDebug("正在查询域控制器...")
2024-12-28 05:43:22 +08:00
dcQuery := ldap.NewSearchRequest(
d.baseDN,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
0,
0,
false,
"(&(objectClass=computer)(userAccountControl:1.2.840.113556.1.4.803:=8192))",
[]string{"cn"},
nil,
)
if sr, err := d.conn.SearchWithPaging(dcQuery, 10000); err == nil {
var dcs []string
for _, entry := range sr.Entries {
name := entry.GetAttributeValue("cn")
if name != "" {
dcs = append(dcs, name)
Common.LogDebug(fmt.Sprintf("发现域控制器: %s", name))
2024-12-28 05:43:22 +08:00
}
}
if len(dcs) > 0 {
results["域控制器"] = dcs
Common.LogSuccess(fmt.Sprintf("共发现 %d 个域控制器", len(dcs)))
} else {
Common.LogDebug("未发现域控制器")
2024-12-28 05:43:22 +08:00
}
} else {
Common.LogError(fmt.Sprintf("查询域控制器时出错: %v", err))
2024-12-28 05:43:22 +08:00
}
// 获取Exchange服务器
Common.LogDebug("正在查询Exchange服务器...")
2024-12-28 05:43:22 +08:00
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("未发现任何特殊计算机")
2024-12-28 05:43:22 +08:00
}
return results, nil
}
func (d *DomainInfo) GetDomainUsers() ([]string, error) {
Common.LogDebug("开始查询域用户...")
2024-12-28 05:43:22 +08:00
searchRequest := ldap.NewSearchRequest(
d.baseDN,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
0,
0,
false,
"(&(objectCategory=person)(objectClass=user))",
[]string{"sAMAccountName"},
nil,
)
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
if err != nil {
Common.LogError(fmt.Sprintf("查询域用户失败: %v", err))
2024-12-28 05:43:22 +08:00
return nil, err
}
var users []string
for _, entry := range sr.Entries {
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("未发现域用户")
2024-12-28 05:43:22 +08:00
}
return users, nil
}
func (d *DomainInfo) GetDomainAdmins() ([]string, error) {
Common.LogDebug("开始查询域管理员...")
2024-12-28 05:43:22 +08:00
searchRequest := ldap.NewSearchRequest(
d.baseDN,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
0,
0,
false,
"(&(objectCategory=group)(cn=Domain Admins))",
[]string{"member", "sAMAccountName"},
nil,
)
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
if err != nil {
Common.LogError(fmt.Sprintf("查询Domain Admins组失败: %v", err))
2024-12-28 05:43:22 +08:00
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)))
2024-12-28 05:43:22 +08:00
for _, memberDN := range members {
memberSearch := ldap.NewSearchRequest(
memberDN,
ldap.ScopeBaseObject,
ldap.NeverDerefAliases,
0,
0,
false,
"(objectClass=*)",
[]string{"sAMAccountName"},
nil,
)
memberResult, err := d.conn.Search(memberSearch)
if err != nil {
Common.LogError(fmt.Sprintf("查询成员 %s 失败: %v", memberDN, err))
continue
2024-12-28 05:43:22 +08:00
}
if len(memberResult.Entries) > 0 {
samAccountName := memberResult.Entries[0].GetAttributeValue("sAMAccountName")
if samAccountName != "" {
admins = append(admins, samAccountName)
Common.LogDebug(fmt.Sprintf("发现域管理员: %s", samAccountName))
2024-12-28 05:43:22 +08:00
}
}
}
}
if len(admins) > 0 {
Common.LogSuccess(fmt.Sprintf("共发现 %d 个域管理员", len(admins)))
} else {
Common.LogDebug("未发现域管理员")
}
2024-12-28 05:43:22 +08:00
return admins, nil
}
func (d *DomainInfo) GetOUs() ([]string, error) {
Common.LogDebug("开始查询组织单位(OU)...")
2024-12-28 05:43:22 +08:00
searchRequest := ldap.NewSearchRequest(
d.baseDN,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
0,
0,
false,
"(objectClass=organizationalUnit)",
[]string{"ou"},
nil,
)
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
if err != nil {
Common.LogError(fmt.Sprintf("查询OU失败: %v", err))
2024-12-28 05:43:22 +08:00
return nil, err
}
var ous []string
for _, entry := range sr.Entries {
ou := entry.GetAttributeValue("ou")
if ou != "" {
ous = append(ous, ou)
Common.LogDebug(fmt.Sprintf("发现OU: %s", ou))
2024-12-28 05:43:22 +08:00
}
}
if len(ous) > 0 {
Common.LogSuccess(fmt.Sprintf("共发现 %d 个组织单位", len(ous)))
} else {
Common.LogDebug("未发现组织单位")
}
2024-12-28 05:43:22 +08:00
return ous, nil
}
func (d *DomainInfo) GetComputers() ([]Computer, error) {
Common.LogDebug("开始查询域内计算机...")
2024-12-28 05:43:22 +08:00
searchRequest := ldap.NewSearchRequest(
d.baseDN,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
0,
0,
false,
"(&(objectClass=computer))",
[]string{"cn", "operatingSystem", "dNSHostName"},
nil,
)
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
if err != nil {
Common.LogError(fmt.Sprintf("查询计算机失败: %v", err))
2024-12-28 05:43:22 +08:00
return nil, err
}
var computers []Computer
for _, entry := range sr.Entries {
computer := Computer{
Name: entry.GetAttributeValue("cn"),
OperatingSystem: entry.GetAttributeValue("operatingSystem"),
DNSHostName: entry.GetAttributeValue("dNSHostName"),
}
computers = append(computers, computer)
Common.LogDebug(fmt.Sprintf("发现计算机: %s (OS: %s, DNS: %s)",
computer.Name,
computer.OperatingSystem,
computer.DNSHostName))
2024-12-28 05:43:22 +08:00
}
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("未发现计算机")
}
2024-12-28 05:43:22 +08:00
return computers, nil
}
// 定义计算机结构体
type Computer struct {
Name string
OperatingSystem string
DNSHostName string
}
func (d *DomainInfo) GetTrustDomains() ([]string, error) {
Common.LogDebug("开始查询域信任关系...")
2024-12-28 05:43:22 +08:00
searchRequest := ldap.NewSearchRequest(
d.baseDN,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
0,
0,
false,
"(&(objectClass=trustedDomain))",
[]string{"cn", "trustDirection", "trustType"},
nil,
)
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
if err != nil {
Common.LogError(fmt.Sprintf("查询信任域失败: %v", err))
2024-12-28 05:43:22 +08:00
return nil, err
}
var trustInfo []string
for _, entry := range sr.Entries {
cn := entry.GetAttributeValue("cn")
if cn != "" {
trustInfo = append(trustInfo, cn)
Common.LogDebug(fmt.Sprintf("发现信任域: %s", cn))
2024-12-28 05:43:22 +08:00
}
}
if len(trustInfo) > 0 {
Common.LogSuccess(fmt.Sprintf("共发现 %d 个信任域", len(trustInfo)))
} else {
Common.LogDebug("未发现信任域关系")
}
2024-12-28 05:43:22 +08:00
return trustInfo, nil
}
func (d *DomainInfo) GetAdminGroups() (map[string][]string, error) {
Common.LogDebug("开始查询管理员组信息...")
2024-12-28 05:43:22 +08:00
adminGroups := map[string]string{
"Domain Admins": "(&(objectClass=group)(cn=Domain Admins))",
"Enterprise Admins": "(&(objectClass=group)(cn=Enterprise Admins))",
"Administrators": "(&(objectClass=group)(cn=Administrators))",
}
results := make(map[string][]string)
for groupName, filter := range adminGroups {
Common.LogDebug(fmt.Sprintf("正在查询 %s 组...", groupName))
2024-12-28 05:43:22 +08:00
searchRequest := ldap.NewSearchRequest(
d.baseDN,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
0,
0,
false,
filter,
[]string{"member"},
nil,
)
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
if err != nil {
Common.LogError(fmt.Sprintf("查询 %s 组失败: %v", groupName, err))
2024-12-28 05:43:22 +08:00
continue
}
if len(sr.Entries) > 0 {
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))
2024-12-28 05:43:22 +08:00
}
}
}
if len(results) > 0 {
Common.LogSuccess(fmt.Sprintf("共发现 %d 个管理员组", len(results)))
} else {
Common.LogDebug("未发现管理员组信息")
}
2024-12-28 05:43:22 +08:00
return results, nil
}
func (d *DomainInfo) GetDelegation() (map[string][]string, error) {
Common.LogDebug("开始查询委派信息...")
2024-12-28 05:43:22 +08:00
delegationQueries := map[string]string{
2024-12-28 06:34:37 +08:00
"非约束委派": "(&(objectCategory=computer)(userAccountControl:1.2.840.113556.1.4.803:=524288))",
"约束委派": "(msDS-AllowedToDelegateTo=*)",
2024-12-28 05:43:22 +08:00
"基于资源的约束委派": "(msDS-AllowedToActOnBehalfOfOtherIdentity=*)",
}
results := make(map[string][]string)
for delegationType, query := range delegationQueries {
Common.LogDebug(fmt.Sprintf("正在查询%s...", delegationType))
2024-12-28 05:43:22 +08:00
searchRequest := ldap.NewSearchRequest(
d.baseDN,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
0,
0,
false,
query,
[]string{"cn", "distinguishedName"},
nil,
)
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
if err != nil {
Common.LogError(fmt.Sprintf("查询%s失败: %v", delegationType, err))
2024-12-28 05:43:22 +08:00
continue
}
var entries []string
for _, entry := range sr.Entries {
cn := entry.GetAttributeValue("cn")
if cn != "" {
entries = append(entries, cn)
Common.LogDebug(fmt.Sprintf("发现%s: %s", delegationType, cn))
2024-12-28 05:43:22 +08:00
}
}
if len(entries) > 0 {
results[delegationType] = entries
Common.LogSuccess(fmt.Sprintf("%s: 发现 %d 条记录", delegationType, len(entries)))
} else {
Common.LogDebug(fmt.Sprintf("未发现%s记录", delegationType))
2024-12-28 05:43:22 +08:00
}
}
if len(results) > 0 {
Common.LogSuccess(fmt.Sprintf("共发现 %d 类委派配置", len(results)))
} else {
Common.LogDebug("未发现任何委派配置")
}
2024-12-28 05:43:22 +08:00
return results, nil
}
// 获取AS-REP Roasting漏洞用户
func (d *DomainInfo) GetAsrepRoastUsers() ([]string, error) {
Common.LogDebug("开始查询AS-REP Roasting漏洞用户...")
2024-12-28 05:43:22 +08:00
searchRequest := ldap.NewSearchRequest(
d.baseDN,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
0,
0,
false,
"(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=4194304))",
[]string{"sAMAccountName"},
nil,
)
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
if err != nil {
Common.LogError(fmt.Sprintf("查询AS-REP Roasting漏洞用户失败: %v", err))
2024-12-28 05:43:22 +08:00
return nil, err
}
var users []string
for _, entry := range sr.Entries {
name := entry.GetAttributeValue("sAMAccountName")
if name != "" {
users = append(users, name)
Common.LogDebug(fmt.Sprintf("发现存在AS-REP Roasting漏洞的用户: %s", name))
2024-12-28 05:43:22 +08:00
}
}
if len(users) > 0 {
Common.LogSuccess(fmt.Sprintf("共发现 %d 个存在AS-REP Roasting漏洞的用户", len(users)))
} else {
Common.LogDebug("未发现存在AS-REP Roasting漏洞的用户")
}
2024-12-28 05:43:22 +08:00
return users, nil
}
func (d *DomainInfo) GetPasswordPolicy() (map[string]string, error) {
Common.LogDebug("开始查询域密码策略...")
2024-12-28 05:43:22 +08:00
searchRequest := ldap.NewSearchRequest(
d.baseDN,
ldap.ScopeBaseObject,
ldap.NeverDerefAliases,
0,
0,
false,
"(objectClass=*)",
[]string{
"maxPwdAge",
"minPwdAge",
"minPwdLength",
"pwdHistoryLength",
"pwdProperties",
"lockoutThreshold",
"lockoutDuration",
},
nil,
)
sr, err := d.conn.Search(searchRequest)
if err != nil {
Common.LogError(fmt.Sprintf("查询密码策略失败: %v", err))
2024-12-28 05:43:22 +08:00
return nil, err
}
if len(sr.Entries) == 0 {
Common.LogError("未找到密码策略信息")
2024-12-28 05:43:22 +08:00
return nil, fmt.Errorf("未找到密码策略信息")
}
policy := make(map[string]string)
entry := sr.Entries[0]
// 转换最大密码期限
2024-12-28 05:43:22 +08:00
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))
2024-12-28 05:43:22 +08:00
}
}
if minLength := entry.GetAttributeValue("minPwdLength"); minLength != "" {
policy["最小密码长度"] = minLength + "个字符"
Common.LogDebug(fmt.Sprintf("最小密码长度: %s个字符", minLength))
2024-12-28 05:43:22 +08:00
}
if historyLength := entry.GetAttributeValue("pwdHistoryLength"); historyLength != "" {
policy["密码历史长度"] = historyLength + "个"
Common.LogDebug(fmt.Sprintf("密码历史长度: %s个", historyLength))
2024-12-28 05:43:22 +08:00
}
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("未获取到任何密码策略配置")
2024-12-28 05:43:22 +08:00
}
return policy, nil
}
func (d *DomainInfo) GetSPNs() (map[string][]string, error) {
Common.LogDebug("开始查询SPN信息...")
2024-12-28 05:43:22 +08:00
searchRequest := ldap.NewSearchRequest(
d.baseDN,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
0,
0,
false,
"(servicePrincipalName=*)",
[]string{"distinguishedName", "servicePrincipalName", "cn"},
nil,
)
sr, err := d.conn.SearchWithPaging(searchRequest, 10000)
if err != nil {
Common.LogError(fmt.Sprintf("查询SPN失败: %v", err))
2024-12-28 05:43:22 +08:00
return nil, err
}
spns := make(map[string][]string)
for _, entry := range sr.Entries {
dn := entry.GetAttributeValue("distinguishedName")
cn := entry.GetAttributeValue("cn")
2024-12-28 05:43:22 +08:00
spnList := entry.GetAttributeValues("servicePrincipalName")
2024-12-28 05:43:22 +08:00
if len(spnList) > 0 {
key := fmt.Sprintf("SPN%s", dn)
2024-12-28 05:43:22 +08:00
spns[key] = spnList
Common.LogDebug(fmt.Sprintf("发现SPN - CN: %s", cn))
for _, spn := range spnList {
Common.LogDebug(fmt.Sprintf(" - %s", spn))
}
2024-12-28 05:43:22 +08:00
}
}
if len(spns) > 0 {
Common.LogSuccess(fmt.Sprintf("共发现 %d 个SPN配置", len(spns)))
} else {
Common.LogDebug("未发现SPN配置")
}
2024-12-28 05:43:22 +08:00
return spns, nil
}
func getDomainController() (string, error) {
Common.LogDebug("开始查询域控制器地址...")
// 尝试使用wmic获取当前域名
Common.LogDebug("正在使用wmic获取域名...")
2024-12-28 05:43:22 +08:00
cmd := exec.Command("wmic", "computersystem", "get", "domain")
output, err := cmd.Output()
if err != nil {
Common.LogError(fmt.Sprintf("获取域名失败: %v", err))
2024-12-28 05:43:22 +08:00
return "", fmt.Errorf("获取域名失败: %v", err)
}
lines := strings.Split(string(output), "\n")
if len(lines) < 2 {
Common.LogError("wmic输出格式异常未找到域名")
2024-12-28 05:43:22 +08:00
return "", fmt.Errorf("未找到域名")
}
domain := strings.TrimSpace(lines[1])
if domain == "" {
Common.LogError("获取到的域名为空")
2024-12-28 05:43:22 +08:00
return "", fmt.Errorf("域名为空")
}
Common.LogDebug(fmt.Sprintf("获取到域名: %s", domain))
2024-12-28 05:43:22 +08:00
// 使用nslookup查询域控制器
Common.LogDebug(fmt.Sprintf("正在使用nslookup查询域控制器 (_ldap._tcp.dc._msdcs.%s)...", domain))
2024-12-28 05:43:22 +08:00
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))
2024-12-28 05:43:22 +08:00
return "", fmt.Errorf("查询域控制器失败: %v", err)
}
// 解析nslookup输出
2024-12-28 05:43:22 +08:00
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))
2024-12-28 05:43:22 +08:00
return dcHost, nil
}
}
}
// 尝试使用域名前缀加DC后缀
Common.LogDebug("未从nslookup获取到域控制器尝试使用域名前缀...")
2024-12-28 05:43:22 +08:00
domainParts := strings.Split(domain, ".")
if len(domainParts) > 0 {
dcHost := fmt.Sprintf("dc.%s", domain)
Common.LogDebug(fmt.Sprintf("使用备选域控制器地址: %s", dcHost))
return dcHost, nil
2024-12-28 05:43:22 +08:00
}
Common.LogError("无法获取域控制器地址")
2024-12-28 05:43:22 +08:00
return "", fmt.Errorf("无法获取域控制器地址")
}
func NewDomainInfo() (*DomainInfo, error) {
Common.LogDebug("开始初始化域信息...")
2024-12-28 05:43:22 +08:00
// 获取域控制器地址
Common.LogDebug("正在获取域控制器地址...")
2024-12-28 05:43:22 +08:00
dcHost, err := getDomainController()
if err != nil {
Common.LogError(fmt.Sprintf("获取域控制器失败: %v", err))
2024-12-28 05:43:22 +08:00
return nil, fmt.Errorf("获取域控制器失败: %v", err)
}
Common.LogDebug(fmt.Sprintf("成功获取域控制器地址: %s", dcHost))
2024-12-28 05:43:22 +08:00
// 创建SSPI客户端
Common.LogDebug("正在创建SSPI客户端...")
2024-12-28 05:43:22 +08:00
ldapClient, err := gssapi.NewSSPIClient()
if err != nil {
Common.LogError(fmt.Sprintf("创建SSPI客户端失败: %v", err))
2024-12-28 05:43:22 +08:00
return nil, fmt.Errorf("创建SSPI客户端失败: %v", err)
}
defer ldapClient.Close()
Common.LogDebug("SSPI客户端创建成功")
2024-12-28 05:43:22 +08:00
// 创建LDAP连接
Common.LogDebug(fmt.Sprintf("正在连接LDAP服务器 ldap://%s:389", dcHost))
2024-12-28 05:43:22 +08:00
conn, err := ldap.DialURL(fmt.Sprintf("ldap://%s:389", dcHost))
if err != nil {
Common.LogError(fmt.Sprintf("LDAP连接失败: %v", err))
2024-12-28 05:43:22 +08:00
return nil, fmt.Errorf("LDAP连接失败: %v", err)
}
Common.LogDebug("LDAP连接建立成功")
2024-12-28 05:43:22 +08:00
// 使用GSSAPI进行绑定
Common.LogDebug(fmt.Sprintf("正在进行GSSAPI绑定 (ldap/%s)...", dcHost))
2024-12-28 05:43:22 +08:00
err = conn.GSSAPIBind(ldapClient, fmt.Sprintf("ldap/%s", dcHost), "")
if err != nil {
conn.Close()
Common.LogError(fmt.Sprintf("GSSAPI绑定失败: %v", err))
2024-12-28 05:43:22 +08:00
return nil, fmt.Errorf("GSSAPI绑定失败: %v", err)
}
Common.LogDebug("GSSAPI绑定成功")
2024-12-28 05:43:22 +08:00
// 获取defaultNamingContext
Common.LogDebug("正在查询defaultNamingContext...")
2024-12-28 05:43:22 +08:00
searchRequest := ldap.NewSearchRequest(
"",
ldap.ScopeBaseObject,
ldap.NeverDerefAliases,
0, 0, false,
"(objectClass=*)",
[]string{"defaultNamingContext"},
nil,
)
result, err := conn.Search(searchRequest)
if err != nil {
conn.Close()
Common.LogError(fmt.Sprintf("获取defaultNamingContext失败: %v", err))
2024-12-28 05:43:22 +08:00
return nil, fmt.Errorf("获取defaultNamingContext失败: %v", err)
}
if len(result.Entries) == 0 {
conn.Close()
Common.LogError("未找到defaultNamingContext")
2024-12-28 05:43:22 +08:00
return nil, fmt.Errorf("未找到defaultNamingContext")
}
baseDN := result.Entries[0].GetAttributeValue("defaultNamingContext")
if baseDN == "" {
Common.LogDebug("defaultNamingContext为空使用备选方法获取BaseDN")
2024-12-28 05:43:22 +08:00
baseDN = getDomainDN(dcHost) // 使用备选方法
}
Common.LogSuccess(fmt.Sprintf("初始化完成使用BaseDN: %s", baseDN))
2024-12-28 05:43:22 +08:00
return &DomainInfo{
conn: conn,
baseDN: baseDN,
}, nil
}
func DCInfoScan(info *Common.HostInfo) (err error) {
// 创建DomainInfo实例
Common.LogDebug("正在初始化域信息...")
2024-12-28 05:43:22 +08:00
di, err := NewDomainInfo()
if err != nil {
Common.LogError(fmt.Sprintf("初始化域信息失败: %v", err))
return err
2024-12-28 05:43:22 +08:00
}
defer di.Close()
// 获取特殊计算机列表
2024-12-28 05:43:22 +08:00
specialComputers, err := di.GetSpecialComputers()
if err != nil {
Common.LogError(fmt.Sprintf("获取特殊计算机失败: %v", err))
2024-12-28 05:43:22 +08:00
} else {
categories := []string{
"SQL服务器",
"CA服务器",
"域控制器",
"Exchange服务器",
}
Common.LogSuccess("[*] 特殊计算机信息:")
2024-12-28 05:43:22 +08:00
for _, category := range categories {
if computers, ok := specialComputers[category]; ok {
Common.LogSuccess(fmt.Sprintf("[+] %s:", category))
2024-12-28 05:43:22 +08:00
for _, computer := range computers {
Common.LogSuccess(fmt.Sprintf(" %s", computer))
2024-12-28 05:43:22 +08:00
}
}
}
}
// 获取域用户
2024-12-28 05:43:22 +08:00
users, err := di.GetDomainUsers()
if err != nil {
Common.LogError(fmt.Sprintf("获取域用户失败: %v", err))
} else {
Common.LogSuccess("[*] 域用户列表:")
for _, user := range users {
Common.LogSuccess(fmt.Sprintf(" %s", user))
}
2024-12-28 05:43:22 +08:00
}
// 获取域管理员
admins, err := di.GetDomainAdmins()
if err != nil {
Common.LogError(fmt.Sprintf("获取域管理员失败: %v", err))
} else {
Common.LogSuccess("[*] 域管理员列表:")
for _, admin := range admins {
Common.LogSuccess(fmt.Sprintf(" %s", admin))
}
2024-12-28 05:43:22 +08:00
}
// 获取组织单位
ous, err := di.GetOUs()
if err != nil {
Common.LogError(fmt.Sprintf("获取组织单位失败: %v", err))
} else {
Common.LogSuccess("[*] 组织单位:")
for _, ou := range ous {
Common.LogSuccess(fmt.Sprintf(" %s", ou))
}
2024-12-28 05:43:22 +08:00
}
// 获取域计算机
computers, err := di.GetComputers()
if err != nil {
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))
}
2024-12-28 05:43:22 +08:00
}
}
// 获取信任域关系
2024-12-28 05:43:22 +08:00
trustDomains, err := di.GetTrustDomains()
if err == nil && len(trustDomains) > 0 {
Common.LogSuccess("[*] 信任域关系:")
2024-12-28 05:43:22 +08:00
for _, domain := range trustDomains {
Common.LogSuccess(fmt.Sprintf(" %s", domain))
2024-12-28 05:43:22 +08:00
}
}
// 获取域管理员组信息
2024-12-28 05:43:22 +08:00
adminGroups, err := di.GetAdminGroups()
if err == nil && len(adminGroups) > 0 {
Common.LogSuccess("[*] 管理员组信息:")
2024-12-28 05:43:22 +08:00
for groupName, members := range adminGroups {
Common.LogSuccess(fmt.Sprintf("[+] %s成员:", groupName))
2024-12-28 05:43:22 +08:00
for _, member := range members {
Common.LogSuccess(fmt.Sprintf(" %s", member))
2024-12-28 05:43:22 +08:00
}
}
}
// 获取委派信息
2024-12-28 05:43:22 +08:00
delegations, err := di.GetDelegation()
if err == nil && len(delegations) > 0 {
Common.LogSuccess("[*] 委派信息:")
2024-12-28 05:43:22 +08:00
for delegationType, entries := range delegations {
Common.LogSuccess(fmt.Sprintf("[+] %s:", delegationType))
2024-12-28 05:43:22 +08:00
for _, entry := range entries {
Common.LogSuccess(fmt.Sprintf(" %s", entry))
2024-12-28 05:43:22 +08:00
}
}
}
// 获取AS-REP Roasting漏洞用户
2024-12-28 05:43:22 +08:00
asrepUsers, err := di.GetAsrepRoastUsers()
if err == nil && len(asrepUsers) > 0 {
Common.LogSuccess("[*] AS-REP弱口令账户:")
2024-12-28 05:43:22 +08:00
for _, user := range asrepUsers {
Common.LogSuccess(fmt.Sprintf(" %s", user))
2024-12-28 05:43:22 +08:00
}
}
// 获取域密码策略
2024-12-28 05:43:22 +08:00
passwordPolicy, err := di.GetPasswordPolicy()
if err == nil && len(passwordPolicy) > 0 {
Common.LogSuccess("[*] 域密码策略:")
2024-12-28 05:43:22 +08:00
for key, value := range passwordPolicy {
Common.LogSuccess(fmt.Sprintf(" %s: %s", key, value))
2024-12-28 05:43:22 +08:00
}
}
// 获取SPN信息
spns, err := di.GetSPNs()
if err != nil {
Common.LogError(fmt.Sprintf("获取SPN信息失败: %v", err))
} else if len(spns) > 0 {
Common.LogSuccess("[*] SPN信息:")
2024-12-28 05:43:22 +08:00
for dn, spnList := range spns {
Common.LogSuccess(fmt.Sprintf("[+] %s", dn))
2024-12-28 05:43:22 +08:00
for _, spn := range spnList {
Common.LogSuccess(fmt.Sprintf(" %s", spn))
2024-12-28 05:43:22 +08:00
}
}
}
2024-12-28 05:43:22 +08:00
return nil
}
// 辅助函数从服务器地址获取域DN
func getDomainDN(server string) string {
parts := strings.Split(server, ".")
var dn []string
for _, part := range parts {
dn = append(dn, fmt.Sprintf("DC=%s", part))
}
return strings.Join(dn, ",")
}