Skip to content

Commit 74936f6

Browse files
committed
Add the ADD_COMPUTER action
1 parent 45674fb commit 74936f6

File tree

1 file changed

+121
-7
lines changed

1 file changed

+121
-7
lines changed

modules/auxiliary/admin/dcerpc/samr_computer.rb

Lines changed: 121 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,16 @@ def initialize(info = {})
3131
'SideEffects' => [ IOC_IN_LOGS ]
3232
},
3333
'Actions' => [
34-
[ 'ADD', { 'Description' => 'Add a computer account' } ],
34+
[ 'ADD_COMPUTER', { 'Description' => 'Add a computer account' } ],
3535
],
36-
'DefaultAction' => 'ADD'
36+
'DefaultAction' => 'ADD_COMPUTER'
3737
)
3838
)
3939

40-
register_options([ Opt::RPORT(445) ])
40+
register_options([
41+
OptString.new('COMPUTER_NAME', [ false, 'The computer name' ]),
42+
Opt::RPORT(445)
43+
])
4144
end
4245

4346
def connect_samr
@@ -73,9 +76,120 @@ def run
7376
fail_with(Module::Failure::Unreachable, "Unable to connect to the remote IPC$ share ([#{e.class}] #{e}).")
7477
end
7578

76-
samr = connect_samr
77-
server_handle = samr.samr_connect(access: 0x30)
78-
domains = samr.samr_enumerate_domains_in_sam_server(server_handle: server_handle)
79-
print_status(domains.inspect)
79+
@samr = connect_samr
80+
@server_handle = @samr.samr_connect
81+
82+
if datastore['SMBDomain'].blank? || datastore['SMBDomain'] == '.'
83+
all_domains = @samr.samr_enumerate_domains_in_sam_server(server_handle: @server_handle).map(&:to_s).map(&:encode)
84+
all_domains.delete('Builtin')
85+
if all_domains.length == 0
86+
fail_with(Failure::NotFound, 'No domains were found on the SAM server.')
87+
elsif all_domains.length > 1
88+
print_status("Enumerated domains: #{all_domains.join(', ')}")
89+
fail_with(Failure::BadConfig, 'The SAM server has more than one domain, the target must be specified.')
90+
end
91+
92+
@domain_name = all_domains.first
93+
print_status("Using automatically identified domain: #{@domain_name}")
94+
else
95+
@domain_name = datastore['SMBDomain']
96+
end
97+
98+
@domain_sid = @samr.samr_lookup_domain(server_handle: @server_handle, name: @domain_name)
99+
@domain_handle = @samr.samr_open_domain(server_handle: @server_handle, domain_id: @domain_sid)
100+
send("action_#{action.name.downcase}")
101+
end
102+
103+
def random_hostname(prefix: 'DESKTOP')
104+
"#{prefix}-#{Rex::Text.rand_base(8, '', ('A'..'Z').to_a + ('0'..'9').to_a)}$"
105+
end
106+
107+
def action_add_computer
108+
if datastore['COMPUTER_NAME'].blank?
109+
computer_name = random_hostname
110+
4.downto(0) do |attempt|
111+
break if @samr.samr_lookup_names_in_domain(domain_handle: @domain_handle, names: [ computer_name ]).nil?
112+
113+
computer_name = random_hostname
114+
fail_with(Failure::BadConfig, 'Could not find an unused computer name.') if attempt == 0
115+
end
116+
else
117+
computer_name = datastore['COMPUTER_NAME']
118+
if @samr.samr_lookup_names_in_domain(domain_handle: @domain_handle, names: [ computer_name ])
119+
fail_with(Failure::BadConfig, 'The specified computer name already exists.')
120+
end
121+
end
122+
123+
result = @samr.samr_create_user2_in_domain(
124+
domain_handle: @domain_handle,
125+
name: computer_name,
126+
account_type: RubySMB::Dcerpc::Samr::USER_WORKSTATION_TRUST_ACCOUNT,
127+
desired_access: RubySMB::Dcerpc::Samr::USER_FORCE_PASSWORD_CHANGE | RubySMB::Dcerpc::Samr::MAXIMUM_ALLOWED
128+
)
129+
130+
user_handle = result[:user_handle]
131+
password = Rex::Text.rand_text_alphanumeric(32)
132+
133+
user_info = RubySMB::Dcerpc::Samr::SamprUserInfoBuffer.new(
134+
tag: RubySMB::Dcerpc::Samr::USER_INTERNAL4_INFORMATION_NEW,
135+
member: RubySMB::Dcerpc::Samr::SamprUserInternal4InformationNew.new(
136+
i1: {
137+
password_expired: 1,
138+
which_fields: RubySMB::Dcerpc::Samr::USER_ALL_NTPASSWORDPRESENT | RubySMB::Dcerpc::Samr::USER_ALL_PASSWORDEXPIRED
139+
},
140+
user_password: {
141+
buffer: RubySMB::Dcerpc::Samr::SamprEncryptedUserPasswordNew.encrypt_password(
142+
password,
143+
@simple.client.application_key.blank? ? @simple.client.session_key : @simple.client.application_key
144+
)
145+
}
146+
)
147+
)
148+
@samr.samr_set_information_user2(
149+
user_handle: user_handle,
150+
user_info: user_info
151+
)
152+
153+
user_info = RubySMB::Dcerpc::Samr::SamprUserInfoBuffer.new(
154+
tag: RubySMB::Dcerpc::Samr::USER_CONTROL_INFORMATION,
155+
member: RubySMB::Dcerpc::Samr::UserControlInformation.new(
156+
user_account_control: RubySMB::Dcerpc::Samr::USER_WORKSTATION_TRUST_ACCOUNT
157+
)
158+
)
159+
@samr.samr_set_information_user2(
160+
user_handle: user_handle,
161+
user_info: user_info
162+
)
163+
print_good("Successfully created #{@domain_name}\\#{computer_name} with password #{password}")
164+
report_creds(@domain_name, computer_name, password)
165+
end
166+
167+
def report_creds(domain, username, password)
168+
service_data = {
169+
address: datastore['RHOST'],
170+
port: datastore['RPORT'],
171+
service_name: 'smb',
172+
protocol: 'tcp',
173+
workspace_id: myworkspace_id
174+
}
175+
176+
credential_data = {
177+
module_fullname: fullname,
178+
origin_type: :service,
179+
private_data: password,
180+
private_type: :password,
181+
username: username,
182+
realm_key: Metasploit::Model::Realm::Key::ACTIVE_DIRECTORY_DOMAIN,
183+
realm_value: domain
184+
}.merge(service_data)
185+
186+
credential_core = create_credential(credential_data)
187+
188+
login_data = {
189+
core: credential_core,
190+
status: Metasploit::Model::Login::Status::UNTRIED
191+
}.merge(service_data)
192+
193+
create_credential_login(login_data)
80194
end
81195
end

0 commit comments

Comments
 (0)