Skip to content
KitploitKITPLOIT
أدواتالمدونة
إرسال
أدواتالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

··الخلاصات·اتصال·الخصوصية·© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
CVE-2024-27198 — تحليل مفصل لـ CVE-2024-27198: تجاوز المصادقة في JetBrains TeamCity يؤدي إلى تنفيذ التعليمات البرمجية عن بُعد، مع شرح على مستوى الكود وعرض الاستغلال. | Kitploit
أدوات/GitHubGitHub/hpt-intern-task-submission/cve-2024-27198
تحليل الثغرات الأمنيةالاستغلالاستغلال تطبيقات الويباختبار الاختراقالمصادقةالتعلم والتعليم
GitHubhpt-intern-task-submission/cve-2024-27198

CVE-2024-27198

تحليل مفصل لـ CVE-2024-27198: تجاوز المصادقة في JetBrains TeamCity يؤدي إلى تنفيذ التعليمات البرمجية عن بُعد، مع شرح على مستوى الكود وعرض الاستغلال.

عرض المستودع
1منذ 2 سنواتلم تتم المراجعة بعد

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة

CVE-2024-27198: تجاوز المصادقة في Jetbrain Teamcity يؤدي إلى تنفيذ التعليمات البرمجية عن بُعد

نظرة عامة

TeamCity هو خادم تكامل مستمر ونشر يوفر اختبارات وحدة مستمرة جاهزة للاستخدام، وتحليل جودة الكود، وتقارير مبكرة عن مشاكل البناء

تظهر الثغرة في مكتبة تسمح للمهاجمين بالوصول إلى نقاط نهاية غير مصادق عليها بشكل تعسفي.

تحليل الكود

الكود القابل للاختراق موجود في مكتبة web-openapi.jar في directory to the lib

الصنف jetbrains.buildServer.controllers.BaseController هو المسؤول عن معالجة الطلبات والاستجابات، ولكنه مُنفَّذ بشكل غير صحيح. دعنا نرى كيف يبدو الكود:

root@kitploit:~
public abstract class BaseController extends AbstractController {
//////
public final ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {  
    try {  
        ModelAndView modelAndView = this.doHandle(request, response);  
        if (modelAndView != null) {  
            if (modelAndView.getView() instanceof RedirectView) {  
                modelAndView.getModel().clear();  
            } else {  
                this.updateViewIfRequestHasJspParameter(request, modelAndView);  
            }  
        }

الغرض الرئيسي من طريقة ModelAndView هو عرض الصفحة المطلوبة في واجهة المستخدم. هنا تبدأ الثغرة. لاحظ أن updateViewIfRequestHasJspParameter سيتم استدعاؤها إذا لم تتم إعادة توجيه طلبنا. للعثور على السبب الجذري للثغرة، نحتاج إلى التعمق أكثر لفهم ذلك.

root@kitploit:~
private void updateViewIfRequestHasJspParameter(@NotNull HttpServletRequest request, @NotNull ModelAndView modelAndView) {  
    boolean isControllerRequestWithViewName = modelAndView.getViewName() != null && !request.getServletPath().endsWith(".jsp");  
    String jspFromRequest = this.getJspFromRequest(request);  
    if (isControllerRequestWithViewName && StringUtil.isNotEmpty(jspFromRequest) && !modelAndView.getViewName().equals(jspFromRequest)) {  
        modelAndView.setViewName(jspFromRequest);  
    }  
  
}

تُستخدم هذه الطريقة لتحديث اسم العرض لكائن ModelAndView عندما تتحقق شروط معينة. سيكون isControllerRequestWithViewName بقيمة True إذا كان كائن modelAndView يحتوي على اسم وكان path في الرابط لا ينتهي بـ .jsp. على سبيل المثال، الرابط الذي يحقق هذه الشروط هو http://localhost:8111/random_string والرابط غير الصالح سيكون http://localhost:8111/admin/admin.html أو http://localhost:8111/admin.jsp. كما ناقشنا أعلاه، يجب ألا نصل إلى أي شيء يسبب إعادة توجيه، وعادةً ما تكون هذه صفحات تتطلب تفويضًا (Authorization). بعد ذلك، سيخصص البرنامج متغيرًا باسم jspFromRequest والذي سيستدعي الطريقة getJspFromRequest(). دعنا ننتقل الآن إلى تلك الطريقة، وسأشرح الكود المتبقي بعد ذلك. توجد عبارة if ستتحقق مما إذا كان isControllerRequestWithViewName صحيحًا، وكانت نتيجة استدعاء الطريقة getJspFromRequest() غير فارغة، ويجب ألا يساوي اسم كائن modelAndView الصفحة التي نريد طلبها عبر

root@kitploit:~
protected String getJspFromRequest(@NotNull HttpServletRequest request) { String  jspFromRequest  = request.getParameter("jsp"); return  jspFromRequest  == null || jspFromRequest.endsWith(".jsp") && !jspFromRequest.contains("admin/") ? jspFromRequest : null; }

ستقوم هذه الدالة أولاً باسترجاع قيمة معامل طلب يُسمى jsp. يضمن الفحص أن jsp يجب أن ينتهي بـ .jsp ويجب ألا يحتوي على /admin. وبدمج ذلك مع عبارة if أعلاه:

root@kitploit:~
if (isControllerRequestWithViewName && StringUtil.isNotEmpty(jspFromRequest) && !modelAndView.getViewName().equals(jspFromRequest)) {  
        modelAndView.setViewName(jspFromRequest);  
    }  

سيكون لدينا صورة شاملة لكيفية شكل الرابط:

  1. يجب ألا يؤدي المسار إلى إعادة توجيه كما يجب ألا يحتوي على .jsp
  2. يجب ألا يساوي معامل الطلب jsp قيمة path. على سبيل المثال، /random?jsp=/random سيكون غير صالح
  3. والأهم من ذلك، يجب أن ينتهي jsp بـ .jsp

توفر TeamCity واجهة برمجة تطبيقات REST لدمج التطبيقات الخارجية وإنشاء تفاعلات برمجية مع خادم TeamCity. كما تسمح بالوصول إلى الموارد عبر مسارات URL. يمكنك البدء في العمل مع REST API بفتح الرابط http://<TeamCity Server host>:<port>/app/rest/server في متصفحك: تعطيك هذه الصفحة عدة مؤشرات لاستكشاف الواجهة.

تقدم TeamCity واجهة REST API تسمح لنا بالوصول إلى الموارد الحساسة إذا تمكنا من تجاوز المصادقة. في هذه الحالة، على سبيل المثال، سنحاول الوصول إلى /app/rest/server.

unauthenticated_request

كالمعتاد، سيعيد الخادم توجيهنا إلى /login.html عندما نطلب /app/rest/server. دعنا ننشئ رابطًا مثاليًا لتجاوز هذا القيد. أولًا، يمكن أن يكون مسارنا أي شيء طالما أنه يُرجع رمز الحالة 404 أو حتى 200 مثل login.html. بعد ذلك، سنستخدم jsp لطلب /app/rest/server، لكن يجب أن ينتهي بـ .jsp. في هذه الحالة، هناك حتى حيلتان يمكننا استخدامهما لتجاوز هذا الفحص. يمكننا استخدام الفاصلة المنقوطة ; كمحدد للمعاملات: /app/rest/server;.jsp، وهذه المرة سيتم التعامل مع .jsp كمعامل ثانٍ. أما التجاوز الثاني فهو استخدام جزء URI #: /app/rest/server%23.jsp. ما يأتي خلف جزء URI لن يُستخدم للتوجيه (Routing)، بل يُستخدم فقط للتنقل في الصفحة. لاحظ أن الحرف يجب أن يكون مرمّزًا لرابط (URL-encoded)، وإلا سيتجاهله المتصفح أولًا.

unauthenticated_request_bypass.png

بهذه التقنية، يمكننا حتى إنشاء مستخدم جديد بصلاحيات مدير (Admin Privilege). ذكرت وثائق TeamCity أنه يمكننا إنشاء مستخدم جديد عبر نقطة النهاية /app/rest/users.

create_new_user

دعنا نذهب إلى لوحة الإدارة ونتحقق مما إذا كان هناك أي مستخدم جديد تم إنشاؤه.

confirmed

كما هو متوقع، تم إنشاء مستخدم جديد بصلاحيات مدير (Admin Privilege). بصلاحيات المدير، يمكننا التحكم الكامل في الخادم. ومع ذلك، يمكننا الذهاب أبعد من ذلك من خلال الحصول على تنفيذ التعليمات البرمجية عن بُعد. هذه الثغرة (CVE) تؤثر على جميع الإصدارات قبل 2023.11.4، لكن هذا الـ RCE ممكن فقط للإصدارات السابقة لـ 2023.11. هناك نقطة نهاية غير موثقة /app/rest/debug/processes تسمح للمستخدم بصلاحيات المدير بتنفيذ أوامر تعسفية. سنرسل طلب POST مع معاملَي طلب في رابط الطلب. لنظام ويندوز سيكون ?exePath=cmd.exe&params=/c%20[our command here] ومع لينكس سيكون ?exePath=/bin/sh&params=-c%20[our command here]. أنا أشغّل TeamCity على ويندوز، لذا سيكون المسار الكامل هو /app/rest/debug/processes?exePath=cmd.exe&params=/c%20whoami

failed_attempt

أعاد الخادم خطأ 403 يفيد بأن الطلب يفتقر إلى csrf token. توفر وثائق TeamCity أيضًا نقطة النهاية لاسترجاع الرمز، وهي /authenticationTest.html?csrf.

بعد استرجاع الرمز، سنضيفه إلى ترويسة الطلب X-TC-CSRF-Token أو معامل HTTP tc-csrf-token، وهنا اخترت X-TC-CSRF-Token.

done

بعد توفير csrf token، نجحنا في تنفيذ الأوامر عن بُعد، مما يمنحنا تحكمًا كاملاً في الخادم.

في هذه الثغرة (CVE)، لم يكن الخلل الأمني في التحقق من المدخلات، بل في منطق الكود. هذا التطبيق معقد حقًا لدرجة أن المطورين سيرتكبون الأخطاء بطريقة ما. تعلمنا أيضًا تقنية جديدة لتجاوز المصادقة. آمل أن تتعلم شيئًا مفيدًا من هذا التحليل. اختراق سعيد!!!

تنزيل الأداة