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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
|
function New-MachineAccount
{
<#
.SYNOPSIS
This function adds a machine account with a specified password to Active Directory through an encrypted LDAP
add request. By default standard domain users can add up to 10 systems to AD (see ms-DS-MachineAccountQuota).
Author: Kevin Robertson (@kevin_robertson)
License: BSD 3-Clause
.DESCRIPTION
The main purpose of this function is to leverage the default ms-DS-MachineAccountQuota attribute setting which
allows all domain users to add up to 10 computers to a domain. The machine account and HOST SPNs are added
directly through an LDAP connection to a domain controller and not by attaching the host system to Active
Directory. This function does not modify the domain attachment and machine account associated with the host
system.
Note that you will not be able to remove the account without elevating privilege. You can however disable the
account as long as you maintain access to the account used to create the machine account.
.PARAMETER Credential
Credentials for adding the machine account. Note that machine accounts can also add machine accounts.
.PARAMETER Domain
The targeted domain. This parameter is mandatory on a non-domain attached system. Note this parameter
requires a DNS domain name and not a NetBIOS version.
.PARAMETER DomainController
Domain controller to target. This parameter is mandatory on a non-domain attached system.
.PARAMETER DistinguishedName
Distinguished name for the computers OU.
.PARAMETER MachineAccount
The username of the machine account that will be added.
.PARAMETER Password
The securestring of the password for the machine account.
.EXAMPLE
New-MachineAccount -MachineAccount iamapc
Add a machine account with the current user's session.
.EXAMPLE
$user_account_creds = Get-Credential
New-MachineAccount -MachineName iamapc -Credential $user_account_creds
Add a machine account with creds from another user.
.EXAMPLE
$machine_account_password = ConvertTo-SecureString 'Summer2018!' -AsPlainText -Force
$user_account_password = ConvertTo-SecureString 'Spring2018!' -AsPlainText -Force
$user_account_creds = New-Object System.Management.Automation.PSCredential('domain\user',$user_account_password)
New-MachineAccount -MachineAccount iamapc -Password $machine_account_password -Credential $user_account_creds
Add a machine account with creds from another user and also avoid the machine account password prompt.
.LINK
https://github.com/Kevin-Robertson/Powermad
#>
[CmdletBinding()]
param
(
[parameter(Mandatory=$false)][String]$DistinguishedName,
[parameter(Mandatory=$false)][String]$Domain,
[parameter(Mandatory=$false)][String]$DomainController,
[parameter(Mandatory=$true)][String]$MachineAccount,
[parameter(Mandatory=$false)][System.Security.SecureString]$Password,
[parameter(Mandatory=$false)][System.Management.Automation.PSCredential]$Credential
)
$null = [System.Reflection.Assembly]::LoadWithPartialName("System.DirectoryServices.Protocols")
if(!$Password)
{
$password = Read-Host -Prompt "Enter a password for the new machine account" -AsSecureString
}
$password_BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password)
$password_cleartext = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($password_BSTR)
if(!$DomainController)
{
try
{
$DomainController = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain().DomainControllers[0].Name
}
catch
{
Write-Output "[-] domain controller not located"
throw
}
}
if(!$Domain)
{
try
{
$Domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain().Name
}
catch
{
$error_message = $_.Exception.Message
$error_message = $error_message -replace "`n",""
Write-Output "[-] $error_message"
throw
}
}
$Domain = $Domain.ToLower()
$machine_account = $MachineAccount
if($MachineAccount.EndsWith('$'))
{
$sam_account = $MachineAccount
$machine_account = $machine_account.SubString(0,$machine_account.Length - 1)
}
else
{
$sam_account = $machine_account + "$"
}
Write-Verbose "[+] SAMAccountName=$sam_account"
if(!$DistinguishedName)
{
$distinguished_name = "CN=$machine_account,CN=Computers"
$DC_array = $Domain.Split(".")
ForEach($DC in $DC_array)
{
$distinguished_name += ",DC=$DC"
}
}
else
{
$distinguished_name = "$DistinguishedName"
}
Write-Verbose "[+] Distinguished Name=$distinguished_name"
$password_cleartext = [System.Text.Encoding]::Unicode.GetBytes('"' + $password_cleartext + '"')
$identifier = New-Object System.DirectoryServices.Protocols.LdapDirectoryIdentifier($DomainController,389)
if($Credential)
{
$connection = New-Object System.DirectoryServices.Protocols.LdapConnection($identifier,$Credential.GetNetworkCredential())
}
else
{
$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
$request.DistinguishedName = $distinguished_name
$request.Attributes.Add((New-Object "System.DirectoryServices.Protocols.DirectoryAttribute" -ArgumentList "objectClass","Computer")) > $null
$request.Attributes.Add((New-Object "System.DirectoryServices.Protocols.DirectoryAttribute" -ArgumentList "SamAccountName",$sam_account)) > $null
$request.Attributes.Add((New-Object "System.DirectoryServices.Protocols.DirectoryAttribute" -ArgumentList "userAccountControl","4096")) > $null
$request.Attributes.Add((New-Object "System.DirectoryServices.Protocols.DirectoryAttribute" -ArgumentList "DnsHostName","$machine_account.$Domain")) > $null
$request.Attributes.Add((New-Object "System.DirectoryServices.Protocols.DirectoryAttribute" -ArgumentList "ServicePrincipalName","HOST/$machine_account.$Domain",
"RestrictedKrbHost/$machine_account.$Domain","HOST/$machine_account","RestrictedKrbHost/$machine_account")) > $null
$request.Attributes.Add((New-Object "System.DirectoryServices.Protocols.DirectoryAttribute" -ArgumentList "unicodePwd",$password_cleartext)) > $null
Remove-Variable password_cleartext
try
{
$connection.SendRequest($request) > $null
Write-Output "[+] machine account $machine_account added"
}
catch
{
$error_message = $_.Exception.Message
$error_message = $error_message -replace "`n",""
Write-Output "[-] $error_message"
if($error_message -eq 'Exception calling "SendRequest" with "1" argument(s): "The server cannot handle directory requests."')
{
Write-Output "[!] User may have reached ms-DS-MachineAccountQuota limit"
}
}
}
|